From 2431c3506ef5b3cc2082137945c71b6fedceface Mon Sep 17 00:00:00 2001 From: Gavin King Date: Thu, 26 Jun 2025 23:42:39 +0200 Subject: [PATCH] minor refactoring to DefaultRefreshEventListener --- .../internal/DefaultMergeEventListener.java | 10 +- .../internal/DefaultRefreshEventListener.java | 110 ++++++++++-------- .../internal/StatelessSessionImpl.java | 8 +- 3 files changed, 73 insertions(+), 55 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultMergeEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultMergeEventListener.java index c4e8d2170bb7..2b2d1db2ce99 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultMergeEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultMergeEventListener.java @@ -423,15 +423,15 @@ protected void entityIsDetached(MergeEvent event, Object copiedId, Object origin final Object id = getDetachedEntityId( event, originalId, persister ); // we must clone embedded composite identifiers, or we will get back the same instance that we pass in // apply the special MERGE fetch profile and perform the resolution (Session#get) - final Object result = session.getLoadQueryInfluencers().fromInternalFetchProfile( - CascadingFetchProfile.MERGE, - () -> session.get( entityName, clonedIdentifier ) - ); + final Object result = + session.getLoadQueryInfluencers() + .fromInternalFetchProfile( CascadingFetchProfile.MERGE, + () -> session.get( entityName, clonedIdentifier ) ); if ( result == null ) { LOG.trace( "Detached instance not found in database" ); // we got here because we assumed that an instance - // with an assigned id and no version was detached, + // with an assigned id and no version was detached // when it was really transient (or deleted) final Boolean knownTransient = persister.isTransient( entity, session ); if ( knownTransient == Boolean.FALSE ) { 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 c155823450ac..c4418fa45b81 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 @@ -15,6 +15,7 @@ import org.hibernate.cache.spi.access.SoftLock; import org.hibernate.engine.internal.Cascade; import org.hibernate.engine.internal.CascadePoint; +import org.hibernate.engine.spi.ActionQueue; import org.hibernate.engine.spi.CascadingActions; import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.PersistenceContext; @@ -62,41 +63,7 @@ public void onRefresh(RefreshEvent event, RefreshContext refreshedAlready) { final PersistenceContext persistenceContext = source.getPersistenceContextInternal(); final Object object = event.getObject(); if ( persistenceContext.reassociateIfUninitializedProxy( object ) ) { - final boolean isTransient = isTransient( event, source, object ); - // If refreshAlready is not empty then the refresh is the result of a - // cascade refresh and the refresh of the parent will take care of initializing the lazy - // entity and setting the correct lock on it, this is needed only when the refresh is called directly on a lazy entity - if ( refreshedAlready.isEmpty() ) { - final LazyInitializer lazyInitializer = extractLazyInitializer( object ); - final EntityPersister persister; - if ( lazyInitializer != null ) { - persister = source.getEntityPersister( lazyInitializer.getEntityName(), object ); - } - else if ( !isTransient ) { - persister = persistenceContext.getEntry( object ).getPersister(); - } - else { - persister = source.getEntityPersister( source.guessEntityName( object ), object ); - } - - refresh( - event, - null, - source, - persister, - lazyInitializer, - null, - persister.getIdentifier( object, event.getSession() ), - persistenceContext - ); - if ( lazyInitializer != null ) { - refreshedAlready.add( lazyInitializer.getImplementation() ); - } - } - - if ( isTransient ) { - source.setReadOnly( object, source.isDefaultReadOnly() ); - } + handleUninitializedProxy( event, refreshedAlready, source, object, persistenceContext ); } else { final Object entity = persistenceContext.unproxyAndReassociate( object ); @@ -109,9 +76,58 @@ else if ( !isTransient ) { } } + private static void handleUninitializedProxy( + RefreshEvent event, + RefreshContext refreshedAlready, + EventSource source, + Object object, + PersistenceContext persistenceContext) { + final boolean isTransient = isTransient( event, source, object ); + // If refreshAlready is nonempty then the refresh is the result of a cascade refresh and the + // refresh of the parent will take care of initializing the lazy entity and setting the + // correct lock. This is needed only when the refresh is called directly on a lazy entity. + if ( refreshedAlready.isEmpty() ) { + final LazyInitializer lazyInitializer = extractLazyInitializer( object ); + final EntityPersister persister = getPersister( lazyInitializer, source, object, isTransient ); + refresh( + event, + null, + source, + persister, + lazyInitializer, + null, + persister.getIdentifier( object, event.getSession() ), + persistenceContext + ); + if ( lazyInitializer != null ) { + refreshedAlready.add( lazyInitializer.getImplementation() ); + } + } + + if ( isTransient ) { + source.setReadOnly( object, source.isDefaultReadOnly() ); + } + } + + private static EntityPersister getPersister( + LazyInitializer lazyInitializer, + EventSource source, + Object object, + boolean isTransient) { + if ( lazyInitializer != null ) { + return source.getEntityPersister( lazyInitializer.getEntityName(), object ); + } + else if ( isTransient ) { + return source.getEntityPersister( source.guessEntityName( object ), object ); + } + else { + return source.getPersistenceContextInternal().getEntry( object ).getPersister(); + } + } + private static boolean isTransient(RefreshEvent event, EventSource source, Object object) { final String entityName = event.getEntityName(); - return entityName != null ? !source.contains( entityName, object) : !source.contains(object); + return entityName == null ? !source.contains( object ) : !source.contains( entityName, object ); } private static void refresh(RefreshEvent event, RefreshContext refreshedAlready, Object object) { @@ -179,25 +195,26 @@ private static void refresh( Object object, EventSource source, EntityPersister persister, - LazyInitializer lazyInitializer, + LazyInitializer initializer, EntityEntry entry, Object id, - PersistenceContext persistenceContext) { + PersistenceContext context) { if ( object != null ) { final var instrumentationMetadata = persister.getBytecodeEnhancementMetadata(); if ( instrumentationMetadata.isEnhancedForLazyLoading() ) { final var interceptor = instrumentationMetadata.extractInterceptor( object ); if ( interceptor != null ) { - // The list of initialized lazy fields have to be cleared in order to refresh them from the database. + // The list of initialized lazy fields has to be cleared + // before refreshing them from the database. interceptor.clearInitializedLazyFields(); } } } - final Object result = source.getLoadQueryInfluencers().fromInternalFetchProfile( - CascadingFetchProfile.REFRESH, - () -> doRefresh( event, source, object, entry, persister, lazyInitializer, id, persistenceContext ) - ); + final Object result = + source.getLoadQueryInfluencers() + .fromInternalFetchProfile( CascadingFetchProfile.REFRESH, + () -> doRefresh( event, source, object, entry, persister, initializer, id, context ) ); UnresolvableObjectException.throwIfNull( result, id, persister.getEntityName() ); } @@ -241,7 +258,7 @@ private static Object doRefresh( if ( currentLockMode.greaterThan( requestedLockMode ) ) { // the requested lock-mode is less restrictive than the current one // - pass along the current lock-mode (after accounting for WRITE) - lockOptionsToUse = event.getLockOptions().makeCopy(); + lockOptionsToUse = lockOptionsToUse.makeCopy(); if ( currentLockMode == LockMode.WRITE || currentLockMode == LockMode.PESSIMISTIC_WRITE || currentLockMode == LockMode.PESSIMISTIC_READ ) { @@ -272,7 +289,7 @@ private static Object doRefresh( final Object result = persister.load( id, object, lockOptionsToUse, source ); if ( result != null ) { - // apply `postRefreshLockMode`, if needed + // apply postRefreshLockMode, if needed if ( postRefreshLockMode != null ) { // if we get here, there was a previous entry, and we need to reset its lock mode // - however, the refresh operation actually creates a new entry, so get it @@ -312,6 +329,7 @@ private static void evictCachedCollections(EntityPersister persister, Object id, private static void evictCachedCollections(Type[] types, Object id, EventSource source) throws HibernateException { final SessionFactoryImplementor factory = source.getFactory(); + final ActionQueue actionQueue = source.getActionQueue(); final MappingMetamodelImplementor metamodel = factory.getMappingMetamodel(); for ( Type type : types ) { if ( type instanceof CollectionType collectionType ) { @@ -327,7 +345,7 @@ private static void evictCachedCollections(Type[] types, Object id, EventSource ); final SoftLock lock = cache.lockItem( source, ck, null ); cache.remove( source, ck ); - source.getActionQueue().registerProcess( (success, session) -> cache.unlockItem( session, ck, lock ) ); + actionQueue.registerProcess( (success, session) -> cache.unlockItem( session, ck, lock ) ); } } else if ( type instanceof ComponentType compositeType ) { diff --git a/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java index 51d2dd3af578..c018b0f2c358 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java @@ -925,10 +925,10 @@ public void refresh(String entityName, Object entity, LockMode lockMode) { } } - final Object result = getLoadQueryInfluencers().fromInternalFetchProfile( - CascadingFetchProfile.REFRESH, - () -> persister.load( id, entity, getNullSafeLockMode( lockMode ), this ) - ); + final Object result = + getLoadQueryInfluencers() + .fromInternalFetchProfile( CascadingFetchProfile.REFRESH, + () -> persister.load( id, entity, getNullSafeLockMode( lockMode ), this ) ); UnresolvableObjectException.throwIfNull( result, id, persister.getEntityName() ); if ( temporaryPersistenceContext.isLoadFinished() ) { temporaryPersistenceContext.clear();