diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultRefreshEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultRefreshEventListener.java index 4003ea70da..724e2e85ce 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultRefreshEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultRefreshEventListener.java @@ -33,6 +33,8 @@ import org.hibernate.loader.ast.spi.CascadingFetchProfile; import org.hibernate.metamodel.spi.MappingMetamodelImplementor; import org.hibernate.persister.collection.CollectionPersister; 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.CompositeType; import org.hibernate.type.Type; @@ -62,7 +64,22 @@ public class DefaultRefreshEventListener implements RefreshEventListener { final PersistenceContext persistenceContext = source.getPersistenceContextInternal(); final Object object = event.getObject(); 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() ); } } @@ -144,9 +161,22 @@ public class DefaultRefreshEventListener implements RefreshEventListener { evictEntity( object, 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( 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() ); } @@ -179,6 +209,7 @@ public class DefaultRefreshEventListener implements RefreshEventListener { Object object, EntityEntry entry, EntityPersister persister, + LazyInitializer lazyInitializer, Object id, PersistenceContext persistenceContext) { // Handle the requested lock-mode (if one) in relation to the entry's (if one) current lock-mode @@ -228,19 +259,32 @@ public class DefaultRefreshEventListener implements RefreshEventListener { persistenceContext.getEntry( result ).setLockMode( postRefreshLockMode ); } - // 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 ( !persister.isMutable() ) { - // this is probably redundant; it should already be read-only - source.setReadOnly( result, true ); - } - else { - source.setReadOnly( result, entry == null ? source.isDefaultReadOnly() : entry.isReadOnly() ); - } + 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; + // If it was transient, then set it to the default for the source. + if ( !persister.isMutable() ) { + return true; + } + else if ( entry != null ) { + return entry.isReadOnly(); + } + else if ( lazyInitializer != null ) { + return lazyInitializer.isReadOnly(); + } + else { + return source.isDefaultReadOnly(); + } + } + private static void evictCachedCollections(EntityPersister persister, Object id, EventSource source) { evictCachedCollections( persister.getPropertyTypes(), id, source ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/readonly/ReadOnlyProxyTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/readonly/ReadOnlyProxyTest.java index 3832c9ee03..fdd3588a6b 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/readonly/ReadOnlyProxyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/readonly/ReadOnlyProxyTest.java @@ -1102,7 +1102,7 @@ public class ReadOnlyProxyTest extends AbstractReadOnlyTest { s.setReadOnly( dp, true ); assertFalse( Hibernate.isInitialized( dp ) ); s.refresh( dp ); - assertFalse( Hibernate.isInitialized( dp ) ); + assertTrue( Hibernate.isInitialized( dp ) ); assertEquals( "original", dp.getDescription() ); assertTrue( Hibernate.isInitialized( dp ) ); dp.setDescription( "changed" ); @@ -1232,7 +1232,7 @@ public class ReadOnlyProxyTest extends AbstractReadOnlyTest { assertTrue( s.isReadOnly( dp ) ); s.evict( dp ); s.refresh( dp ); - assertFalse( Hibernate.isInitialized( dp ) ); + assertTrue( Hibernate.isInitialized( dp ) ); assertFalse( s.isReadOnly( dp ) ); dp.setDescription( "changed" ); assertEquals( "changed", dp.getDescription() ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/readonly/ReadOnlySessionTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/readonly/ReadOnlySessionTest.java index 59897eba3f..e46e1d5381 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/readonly/ReadOnlySessionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/readonly/ReadOnlySessionTest.java @@ -516,11 +516,11 @@ public class ReadOnlySessionTest extends AbstractReadOnlyTest { assertTrue( s.isReadOnly( dp ) ); assertFalse( Hibernate.isInitialized( dp ) ); s.refresh( dp ); - assertFalse( Hibernate.isInitialized( dp ) ); + assertTrue( Hibernate.isInitialized( dp ) ); assertTrue( s.isReadOnly( dp ) ); s.setDefaultReadOnly( false ); s.refresh( dp ); - assertFalse( Hibernate.isInitialized( dp ) ); + assertTrue( Hibernate.isInitialized( dp ) ); assertTrue( s.isReadOnly( dp ) ); assertEquals( "original", dp.getDescription() ); assertTrue( Hibernate.isInitialized( dp ) ); @@ -574,12 +574,12 @@ public class ReadOnlySessionTest extends AbstractReadOnlyTest { assertTrue( s.isReadOnly( dp ) ); s.evict( dp ); s.refresh( dp ); - assertFalse( Hibernate.isInitialized( dp ) ); + assertTrue( Hibernate.isInitialized( dp ) ); s.setDefaultReadOnly( false ); assertTrue( s.isReadOnly( dp ) ); s.evict( dp ); s.refresh( dp ); - assertFalse( Hibernate.isInitialized( dp ) ); + assertTrue( Hibernate.isInitialized( dp ) ); assertFalse( s.isReadOnly( dp ) ); assertFalse( s.isReadOnly( ( (HibernateProxy) dp ).getHibernateLazyInitializer().getImplementation() ) ); dp.setDescription( "changed" );