From 6eb729003a8d664beab9a62d8a6180745657faea Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Wed, 26 Feb 2020 14:41:09 +0000 Subject: [PATCH] Fix initialization of empty collections --- ...bstractImmediateCollectionInitializer.java | 18 +++-- .../DelayedCollectionInitializer.java | 67 ++++++++++++++++++- 2 files changed, 78 insertions(+), 7 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/AbstractImmediateCollectionInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/AbstractImmediateCollectionInitializer.java index 7d9c6877a9..0d7d2f8dfb 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/AbstractImmediateCollectionInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/AbstractImmediateCollectionInitializer.java @@ -67,11 +67,25 @@ public abstract class AbstractImmediateCollectionInitializer extends AbstractCol return; } + final PluralAttributeMapping collectionAttributeMapping = getCollectionAttributeMapping(); + final CollectionPersister collectionDescriptor = collectionAttributeMapping.getCollectionDescriptor(); + final CollectionSemantics collectionSemantics = collectionDescriptor.getCollectionSemantics(); + final SharedSessionContractImplementor session = rowProcessingState.getSession(); final PersistenceContext persistenceContext = session.getPersistenceContext(); final CollectionKey collectionKey = resolveCollectionKey( rowProcessingState ); + if ( collectionKey == null ) { + collectionInstance = collectionSemantics.instantiateWrapper( + null, + collectionDescriptor, + session + ); + collectionInstance.initializeEmptyCollection( collectionDescriptor ); + persistenceContext.addNonLazyCollection( collectionInstance ); + } + if ( CollectionLoadingLogger.TRACE_ENABLED ) { CollectionLoadingLogger.INSTANCE.tracef( "(%s) Beginning Initializer#resolveInstance for collection : %s", @@ -92,10 +106,6 @@ public abstract class AbstractImmediateCollectionInitializer extends AbstractCol // final LoadingCollectionEntry existingLoadingEntry = rowProcessingState.getJdbcValuesSourceProcessingState() // .findLoadingCollectionLocally( getCollectionDescriptor(), collectionKey.getKey() ); - final PluralAttributeMapping collectionAttributeMapping = getCollectionAttributeMapping(); - final CollectionPersister collectionDescriptor = collectionAttributeMapping.getCollectionDescriptor(); - final CollectionSemantics collectionSemantics = collectionDescriptor.getCollectionSemantics(); - if ( existingLoadingEntry != null ) { collectionInstance = existingLoadingEntry.getCollectionInstance(); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/DelayedCollectionInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/DelayedCollectionInitializer.java index 3edc4cff3a..3d0c706fca 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/DelayedCollectionInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/DelayedCollectionInitializer.java @@ -12,13 +12,16 @@ import org.hibernate.engine.spi.CollectionKey; import org.hibernate.engine.spi.PersistenceContext; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.internal.log.LoggingHelper; -import org.hibernate.metamodel.CollectionClassification; import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.query.NavigablePath; import org.hibernate.sql.results.graph.FetchParentAccess; import org.hibernate.sql.results.graph.collection.CollectionInitializer; import org.hibernate.sql.results.graph.collection.LoadingCollectionEntry; +import org.hibernate.sql.results.graph.Initializer; +import org.hibernate.sql.results.graph.collection.CollectionInitializer; +import org.hibernate.sql.results.graph.collection.LoadingCollectionEntry; +import org.hibernate.sql.results.graph.entity.EntityInitializer; import org.hibernate.sql.results.jdbc.spi.RowProcessingState; /** @@ -67,12 +70,32 @@ public class DelayedCollectionInitializer implements CollectionInitializer { @Override public void resolveInstance(RowProcessingState rowProcessingState) { + final SharedSessionContractImplementor session = rowProcessingState.getSession(); + final PersistenceContext persistenceContext = session.getPersistenceContext(); if ( collectionKey != null ) { final SharedSessionContractImplementor session = rowProcessingState.getSession(); final PersistenceContext persistenceContext = session.getPersistenceContext(); + if ( collectionKey != null ) { + EntityInitializer entityInitializer = getEntityInitializer( rowProcessingState ); + + + final Object entityUsingInterceptor = persistenceContext.getEntity( entityInitializer.getEntityKey() ); + if ( entityUsingInterceptor != null ) { + return; + } + final Object key = collectionKey.getKey(); + final LoadingCollectionEntry loadingEntry = persistenceContext.getLoadContexts() + .findLoadingCollectionEntry( collectionKey ); + final PersistentCollection registeredInstance = persistenceContext.getCollection( collectionKey ); + final Object key = collectionKey.getKey(); + + if ( loadingEntry != null ) { + instance = loadingEntry.getCollectionInstance(); + return; + } final LoadingCollectionEntry loadingEntry = persistenceContext.getLoadContexts() .findLoadingCollectionEntry( collectionKey ); @@ -81,6 +104,9 @@ public class DelayedCollectionInitializer implements CollectionInitializer { return; } + if ( registeredInstance != null ) { + instance = registeredInstance; + return; final PersistentCollection existing = persistenceContext.getCollection( collectionKey ); if ( existing != null ) { @@ -88,10 +114,38 @@ public class DelayedCollectionInitializer implements CollectionInitializer { return; } + instance = makePersistentCollection( fetchedMapping, key, rowProcessingState ); + + persistenceContext.addUninitializedCollection( + getInitializingCollectionDescriptor(), + instance, + key + ); + } + else { + instance = makePersistentCollection( fetchedMapping, collectionKey, rowProcessingState ); + instance.initializeEmptyCollection( getInitializingCollectionDescriptor() ); + persistenceContext.addNonLazyCollection( instance ); + } + } + + private static PersistentCollection makePersistentCollection( + PluralAttributeMapping fetchedMapping, + Object collectionKey, + RowProcessingState rowProcessingState) { + final CollectionPersister collectionDescriptor = fetchedMapping.getCollectionDescriptor(); + final CollectionSemantics collectionSemantics = collectionDescriptor.getCollectionSemantics(); + final CollectionPersister collectionDescriptor = fetchedMapping.getCollectionDescriptor(); final CollectionSemantics collectionSemantics = collectionDescriptor.getCollectionSemantics(); + return collectionSemantics.instantiateWrapper( + collectionKey, + collectionDescriptor, + rowProcessingState.getSession() + ); + } collectionInstance = collectionSemantics.instantiateWrapper( key, collectionDescriptor, @@ -108,12 +162,19 @@ public class DelayedCollectionInitializer implements CollectionInitializer { key ); + private EntityInitializer getEntityInitializer(RowProcessingState rowProcessingState) { + Initializer initializer = rowProcessingState.resolveInitializer( getNavigablePath().getParent() ); + while ( !( initializer instanceof EntityInitializer ) ) { + initializer = rowProcessingState.resolveInitializer( initializer.getNavigablePath().getParent() ); if ( collectionSemantics.getCollectionClassification() == CollectionClassification.ARRAY ) { session.getPersistenceContext().addCollectionHolder( collectionInstance ); } } + return (EntityInitializer) initializer; + } + @Override public void initializeInstance(RowProcessingState rowProcessingState) { } @@ -126,7 +187,7 @@ public class DelayedCollectionInitializer implements CollectionInitializer { @Override public void finishUpRow(RowProcessingState rowProcessingState) { collectionKey = null; - collectionInstance = null; + instance = null; } @Override @@ -136,7 +197,7 @@ public class DelayedCollectionInitializer implements CollectionInitializer { @Override public PersistentCollection getCollectionInstance() { - return collectionInstance; + return instance; } @Override