HHH-1645 HHH-17395 Refresh with LockMode on an unitialized proxy does not work

This commit is contained in:
Andrea Boriero 2023-12-18 13:07:00 +01:00 committed by Christian Beikov
parent 839c695c8e
commit d085936fcb
3 changed files with 61 additions and 17 deletions

View File

@ -33,6 +33,8 @@ import org.hibernate.loader.ast.spi.CascadingFetchProfile;
import org.hibernate.metamodel.spi.MappingMetamodelImplementor; import org.hibernate.metamodel.spi.MappingMetamodelImplementor;
import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer;
import org.hibernate.type.CollectionType; import org.hibernate.type.CollectionType;
import org.hibernate.type.CompositeType; import org.hibernate.type.CompositeType;
import org.hibernate.type.Type; import org.hibernate.type.Type;
@ -62,7 +64,22 @@ public class DefaultRefreshEventListener implements RefreshEventListener {
final PersistenceContext persistenceContext = source.getPersistenceContextInternal(); final PersistenceContext persistenceContext = source.getPersistenceContextInternal();
final Object object = event.getObject(); final Object object = event.getObject();
if ( persistenceContext.reassociateIfUninitializedProxy( object ) ) { if ( persistenceContext.reassociateIfUninitializedProxy( object ) ) {
if ( isTransient( event, source, object ) ) { final boolean isTransient = isTransient( event, source, object );
final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( object );
final EntityPersister persister = source.getEntityPersister( lazyInitializer.getEntityName(), object );
refresh(
event,
null,
source,
persister,
lazyInitializer,
null,
persister.getIdentifier( object, event.getSession() ),
persistenceContext
);
if ( isTransient ) {
source.setReadOnly( object, source.isDefaultReadOnly() ); source.setReadOnly( object, source.isDefaultReadOnly() );
} }
} }
@ -144,9 +161,22 @@ public class DefaultRefreshEventListener implements RefreshEventListener {
evictEntity( object, persister, id, source ); evictEntity( object, persister, id, source );
evictCachedCollections( persister, id, source ); evictCachedCollections( persister, id, source );
refresh( event, object, source, persister, null, entry, id, persistenceContext );
}
private static void refresh(
RefreshEvent event,
Object object,
EventSource source,
EntityPersister persister,
LazyInitializer lazyInitializer,
EntityEntry entry,
Object id,
PersistenceContext persistenceContext) {
final Object result = source.getLoadQueryInfluencers().fromInternalFetchProfile( final Object result = source.getLoadQueryInfluencers().fromInternalFetchProfile(
CascadingFetchProfile.REFRESH, CascadingFetchProfile.REFRESH,
() -> doRefresh( event, source, object, entry, persister, id, persistenceContext ) () -> doRefresh( event, source, object, entry, persister, lazyInitializer, id, persistenceContext )
); );
UnresolvableObjectException.throwIfNull( result, id, persister.getEntityName() ); UnresolvableObjectException.throwIfNull( result, id, persister.getEntityName() );
} }
@ -179,6 +209,7 @@ public class DefaultRefreshEventListener implements RefreshEventListener {
Object object, Object object,
EntityEntry entry, EntityEntry entry,
EntityPersister persister, EntityPersister persister,
LazyInitializer lazyInitializer,
Object id, Object id,
PersistenceContext persistenceContext) { PersistenceContext persistenceContext) {
// Handle the requested lock-mode (if one) in relation to the entry's (if one) current lock-mode // Handle the requested lock-mode (if one) in relation to the entry's (if one) current lock-mode
@ -228,18 +259,31 @@ public class DefaultRefreshEventListener implements RefreshEventListener {
persistenceContext.getEntry( result ).setLockMode( postRefreshLockMode ); persistenceContext.getEntry( result ).setLockMode( postRefreshLockMode );
} }
source.setReadOnly( result, isReadOnly( entry, persister, lazyInitializer, source ) );
}
return result;
}
private static boolean isReadOnly(
EntityEntry entry,
EntityPersister persister,
LazyInitializer lazyInitializer,
EventSource source) {
// Keep the same read-only/modifiable setting for the entity that it had before refreshing; // Keep the same read-only/modifiable setting for the entity that it had before refreshing;
// If it was transient, then set it to the default for the source. // If it was transient, then set it to the default for the source.
if ( !persister.isMutable() ) { if ( !persister.isMutable() ) {
// this is probably redundant; it should already be read-only return true;
source.setReadOnly( result, true ); }
else if ( entry != null ) {
return entry.isReadOnly();
}
else if ( lazyInitializer != null ) {
return lazyInitializer.isReadOnly();
} }
else { else {
source.setReadOnly( result, entry == null ? source.isDefaultReadOnly() : entry.isReadOnly() ); return source.isDefaultReadOnly();
} }
} }
return result;
}
private static void evictCachedCollections(EntityPersister persister, Object id, EventSource source) { private static void evictCachedCollections(EntityPersister persister, Object id, EventSource source) {
evictCachedCollections( persister.getPropertyTypes(), id, source ); evictCachedCollections( persister.getPropertyTypes(), id, source );

View File

@ -1102,7 +1102,7 @@ public class ReadOnlyProxyTest extends AbstractReadOnlyTest {
s.setReadOnly( dp, true ); s.setReadOnly( dp, true );
assertFalse( Hibernate.isInitialized( dp ) ); assertFalse( Hibernate.isInitialized( dp ) );
s.refresh( dp ); s.refresh( dp );
assertFalse( Hibernate.isInitialized( dp ) ); assertTrue( Hibernate.isInitialized( dp ) );
assertEquals( "original", dp.getDescription() ); assertEquals( "original", dp.getDescription() );
assertTrue( Hibernate.isInitialized( dp ) ); assertTrue( Hibernate.isInitialized( dp ) );
dp.setDescription( "changed" ); dp.setDescription( "changed" );
@ -1232,7 +1232,7 @@ public class ReadOnlyProxyTest extends AbstractReadOnlyTest {
assertTrue( s.isReadOnly( dp ) ); assertTrue( s.isReadOnly( dp ) );
s.evict( dp ); s.evict( dp );
s.refresh( dp ); s.refresh( dp );
assertFalse( Hibernate.isInitialized( dp ) ); assertTrue( Hibernate.isInitialized( dp ) );
assertFalse( s.isReadOnly( dp ) ); assertFalse( s.isReadOnly( dp ) );
dp.setDescription( "changed" ); dp.setDescription( "changed" );
assertEquals( "changed", dp.getDescription() ); assertEquals( "changed", dp.getDescription() );

View File

@ -516,11 +516,11 @@ public class ReadOnlySessionTest extends AbstractReadOnlyTest {
assertTrue( s.isReadOnly( dp ) ); assertTrue( s.isReadOnly( dp ) );
assertFalse( Hibernate.isInitialized( dp ) ); assertFalse( Hibernate.isInitialized( dp ) );
s.refresh( dp ); s.refresh( dp );
assertFalse( Hibernate.isInitialized( dp ) ); assertTrue( Hibernate.isInitialized( dp ) );
assertTrue( s.isReadOnly( dp ) ); assertTrue( s.isReadOnly( dp ) );
s.setDefaultReadOnly( false ); s.setDefaultReadOnly( false );
s.refresh( dp ); s.refresh( dp );
assertFalse( Hibernate.isInitialized( dp ) ); assertTrue( Hibernate.isInitialized( dp ) );
assertTrue( s.isReadOnly( dp ) ); assertTrue( s.isReadOnly( dp ) );
assertEquals( "original", dp.getDescription() ); assertEquals( "original", dp.getDescription() );
assertTrue( Hibernate.isInitialized( dp ) ); assertTrue( Hibernate.isInitialized( dp ) );
@ -574,12 +574,12 @@ public class ReadOnlySessionTest extends AbstractReadOnlyTest {
assertTrue( s.isReadOnly( dp ) ); assertTrue( s.isReadOnly( dp ) );
s.evict( dp ); s.evict( dp );
s.refresh( dp ); s.refresh( dp );
assertFalse( Hibernate.isInitialized( dp ) ); assertTrue( Hibernate.isInitialized( dp ) );
s.setDefaultReadOnly( false ); s.setDefaultReadOnly( false );
assertTrue( s.isReadOnly( dp ) ); assertTrue( s.isReadOnly( dp ) );
s.evict( dp ); s.evict( dp );
s.refresh( dp ); s.refresh( dp );
assertFalse( Hibernate.isInitialized( dp ) ); assertTrue( Hibernate.isInitialized( dp ) );
assertFalse( s.isReadOnly( dp ) ); assertFalse( s.isReadOnly( dp ) );
assertFalse( s.isReadOnly( ( (HibernateProxy) dp ).getHibernateLazyInitializer().getImplementation() ) ); assertFalse( s.isReadOnly( ( (HibernateProxy) dp ).getHibernateLazyInitializer().getImplementation() ) );
dp.setDescription( "changed" ); dp.setDescription( "changed" );