diff --git a/hibernate-core/src/main/java/org/hibernate/collection/spi/InitializerProducerBuilder.java b/hibernate-core/src/main/java/org/hibernate/collection/spi/InitializerProducerBuilder.java index bdd2d14b6b70..cf7c7c887cce 100644 --- a/hibernate-core/src/main/java/org/hibernate/collection/spi/InitializerProducerBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/collection/spi/InitializerProducerBuilder.java @@ -33,25 +33,18 @@ public static CollectionInitializerProducer createInitializerProducer( Fetch indexFetch, Fetch elementFetch, DomainResultCreationState creationState) { - switch ( classification ) { - case ARRAY: - return createArrayInitializerProducer( navigablePath, attributeMapping, fetchParent, selected, indexFetch, elementFetch, creationState ); - case BAG: - case ID_BAG: - return createBagInitializerProducer( navigablePath, attributeMapping, fetchParent, selected, elementFetch, creationState ); - case LIST: - return createListInitializerProducer( navigablePath, attributeMapping, fetchParent, selected, indexFetch, elementFetch, creationState ); - case MAP: - case ORDERED_MAP: - case SORTED_MAP: - return createMapInitializerProducer( navigablePath, attributeMapping, fetchParent, selected, indexFetch, elementFetch, creationState ); - case SET: - case ORDERED_SET: - case SORTED_SET: - return createSetInitializerProducer( navigablePath, attributeMapping, fetchParent, selected, elementFetch, creationState ); - default: - throw new IllegalArgumentException( "Unknown CollectionClassification : " + classification ); - } + return switch ( classification ) { + case ARRAY -> + createArrayInitializerProducer( navigablePath, attributeMapping, fetchParent, selected, indexFetch, elementFetch, creationState ); + case BAG, ID_BAG -> + createBagInitializerProducer( navigablePath, attributeMapping, fetchParent, selected, elementFetch, creationState ); + case LIST -> + createListInitializerProducer( navigablePath, attributeMapping, fetchParent, selected, indexFetch, elementFetch, creationState ); + case MAP, ORDERED_MAP, SORTED_MAP -> + createMapInitializerProducer( navigablePath, attributeMapping, fetchParent, selected, indexFetch, elementFetch, creationState ); + case SET, ORDERED_SET, SORTED_SET -> + createSetInitializerProducer( navigablePath, attributeMapping, fetchParent, selected, elementFetch, creationState ); + }; } public static CollectionInitializerProducer createArrayInitializerProducer( @@ -219,54 +212,19 @@ public static CollectionInitializerProducer createCollectionTypeWrapperInitializ Fetch indexFetch, Fetch elementFetch, DomainResultCreationState creationState) { - switch ( classification ) { - case ARRAY: - return createArrayInitializerProducer( - navigablePath, - attributeMapping, - fetchParent, - selected, - indexFetch, - elementFetch, - creationState - ); - case BAG: - case ID_BAG: + return switch ( classification ) { + case ARRAY -> createArrayInitializerProducer( + navigablePath, + attributeMapping, + fetchParent, + selected, + indexFetch, + elementFetch, + creationState + ); + case BAG, ID_BAG -> { assert indexFetch == null; - return createBagInitializerProducer( - navigablePath, - attributeMapping, - fetchParent, - selected, - elementFetch, - creationState - ); - case LIST: - return createListInitializerProducer( - navigablePath, - attributeMapping, - fetchParent, - selected, - indexFetch, - elementFetch, - creationState - ); - case MAP: - case ORDERED_MAP: - case SORTED_MAP: - return createMapInitializerProducer( - navigablePath, - attributeMapping, - fetchParent, - selected, - indexFetch, - elementFetch, - creationState - ); - case SET: - case ORDERED_SET: - case SORTED_SET: - return createSetInitializerProducer( + yield createBagInitializerProducer( navigablePath, attributeMapping, fetchParent, @@ -274,9 +232,34 @@ public static CollectionInitializerProducer createCollectionTypeWrapperInitializ elementFetch, creationState ); - default: - throw new IllegalArgumentException( "Unknown CollectionClassification : " + classification ); - } + } + case LIST -> createListInitializerProducer( + navigablePath, + attributeMapping, + fetchParent, + selected, + indexFetch, + elementFetch, + creationState + ); + case MAP, ORDERED_MAP, SORTED_MAP -> createMapInitializerProducer( + navigablePath, + attributeMapping, + fetchParent, + selected, + indexFetch, + elementFetch, + creationState + ); + case SET, ORDERED_SET, SORTED_SET -> createSetInitializerProducer( + navigablePath, + attributeMapping, + fetchParent, + selected, + elementFetch, + creationState + ); + }; } private InitializerProducerBuilder() { diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/PluralAttributeMetadataImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/PluralAttributeMetadataImpl.java index 3a3d25a1c3c0..ad3758e30352 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/PluralAttributeMetadataImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/PluralAttributeMetadataImpl.java @@ -45,7 +45,7 @@ class PluralAttributeMetadataImpl this.elementClassification = elementClassification; this.listIndexOrMapKeyClassification = listIndexOrMapKeyClassification; - final ParameterizedType signatureType = AttributeFactory.getSignatureType( member ); + final var signatureType = AttributeFactory.getSignatureType( member ); switch ( collectionClassification ) { case MAP: case SORTED_MAP: @@ -53,21 +53,17 @@ class PluralAttributeMetadataImpl keyJavaType = signatureType != null ? getClassFromGenericArgument( signatureType.getActualTypeArguments()[0] ) : Object.class; - elementJavaType = signatureType != null ? getClassFromGenericArgument( signatureType.getActualTypeArguments()[1] ) : Object.class; - break; } case ARRAY: case LIST: { keyJavaType = Integer.class; - elementJavaType = signatureType != null ? getClassFromGenericArgument( signatureType.getActualTypeArguments()[0] ) : Object.class; - break; } default: { @@ -130,14 +126,11 @@ public AttributeMetadata getAttributeMetadata() { } private static ValueClassification toValueClassification(AttributeClassification classification) { - switch ( classification ) { - case EMBEDDED: - return ValueClassification.EMBEDDABLE; - case BASIC: - return ValueClassification.BASIC; - default: - return ValueClassification.ENTITY; - } + return switch ( classification ) { + case EMBEDDED -> ValueClassification.EMBEDDABLE; + case BASIC -> ValueClassification.BASIC; + default -> ValueClassification.ENTITY; + }; } private Class getClassFromGenericArgument(java.lang.reflect.Type type) { @@ -165,7 +158,7 @@ else if ( type instanceof WildcardType wildcardType ) { } public static CollectionClassification determineCollectionType(Class javaType, Property property) { - final Collection collection = (Collection) property.getValue(); + final var collection = (Collection) property.getValue(); if ( java.util.List.class.isAssignableFrom( javaType ) ) { return CollectionClassification.LIST; diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java index f9e1afb00473..736330398a7a 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java @@ -316,8 +316,7 @@ default String[] getSynchronizedQuerySpaces() { } default void visitQuerySpaces(Consumer querySpaceConsumer) { - final String[] spaces = getSynchronizedQuerySpaces(); - for (String space : spaces) { + for ( String space : getSynchronizedQuerySpaces() ) { querySpaceConsumer.accept(space); } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/DomainResultAssembler.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/DomainResultAssembler.java index 5cef5b01df5f..3df35ffd7e8c 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/DomainResultAssembler.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/DomainResultAssembler.java @@ -50,7 +50,17 @@ default void resolveState(RowProcessingState rowProcessingState) { * {@link Initializer#isResultInitializer()}. */ default void forEachResultAssembler(BiConsumer, X> consumer, X arg) { + } + + default boolean isEager() { + final var initializer = getInitializer(); + return initializer != null && initializer.isEager(); + } + default boolean hasLazySubInitializers() { + final var initializer = getInitializer(); + return initializer != null + && ( !initializer.isEager() || initializer.hasLazySubInitializers() ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/AbstractCollectionInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/AbstractCollectionInitializer.java index aac074e8b48f..23232264aa22 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/AbstractCollectionInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/AbstractCollectionInitializer.java @@ -9,7 +9,6 @@ import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.engine.spi.CollectionKey; import org.hibernate.metamodel.mapping.PluralAttributeMapping; -import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.results.graph.AssemblerCreationState; import org.hibernate.sql.results.graph.DomainResult; @@ -150,8 +149,8 @@ protected void setMissing(Data data) { } protected void resolveCollectionKey(Data data, boolean checkPreviousRow) { - final CollectionKey oldKey = data.collectionKey; - final PersistentCollection oldCollectionInstance = data.getCollectionInstance(); + final var oldKey = data.collectionKey; + final var oldCollectionInstance = data.getCollectionInstance(); data.collectionKey = null; data.setCollectionInstance( null ); @@ -170,7 +169,7 @@ protected void resolveCollectionKey(Data data, boolean checkPreviousRow) { return; } } - final CollectionPersister persister = collectionAttributeMapping.getCollectionDescriptor(); + final var persister = collectionAttributeMapping.getCollectionDescriptor(); // Try to reuse the previous collection key and collection if possible if ( checkPreviousRow && oldKey != null && areKeysEqual( oldKey.getKey(), data.collectionKeyValue ) ) { data.collectionKey = oldKey; @@ -187,10 +186,17 @@ private boolean areKeysEqual(Object key1, Object key2) { return keyTypeForEqualsHashCode == null ? key1.equals( key2 ) : keyTypeForEqualsHashCode.isEqual( key1, key2 ); } + PersistentCollection getCollection(CollectionInitializerData data, Object instance) { + return collectionAttributeMapping.getCollectionDescriptor().isArray() + ? data.getRowProcessingState().getSession().getPersistenceContextInternal() + .getCollectionHolder( instance ) + : (PersistentCollection) instance; + } + @Override protected void forEachSubInitializer(BiConsumer, RowProcessingState> consumer, InitializerData data) { if ( collectionKeyResultAssembler != null ) { - final Initializer initializer = collectionKeyResultAssembler.getInitializer(); + final var initializer = collectionKeyResultAssembler.getInitializer(); if ( initializer != null ) { consumer.accept( initializer, data.getRowProcessingState() ); } @@ -199,8 +205,9 @@ protected void forEachSubInitializer(BiConsumer, RowProcessingSta @Override public @Nullable PersistentCollection getCollectionInstance(Data data) { - return data.getState() == State.UNINITIALIZED || data.getState() == State.MISSING ? null : - data.getCollectionInstance(); + return data.getState() == State.UNINITIALIZED || data.getState() == State.MISSING + ? null + : data.getCollectionInstance(); } @Override 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 a28f746c9777..c9b700fcd633 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 @@ -8,14 +8,11 @@ import java.util.function.BiConsumer; import org.hibernate.LockMode; -import org.hibernate.collection.spi.CollectionSemantics; import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.engine.spi.CollectionKey; import org.hibernate.engine.spi.PersistenceContext; import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.metamodel.CollectionClassification; import org.hibernate.metamodel.mapping.PluralAttributeMapping; -import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.results.graph.AssemblerCreationState; import org.hibernate.sql.results.graph.DomainResult; @@ -81,9 +78,10 @@ public AbstractImmediateCollectionInitializer( isResultInitializer, creationState ); - this.collectionValueKeyResultAssembler = collectionKeyResult == collectionValueKeyResult - ? null - : collectionValueKeyResult.createResultAssembler( this, creationState ); + collectionValueKeyResultAssembler = + collectionKeyResult == collectionValueKeyResult + ? null + : collectionValueKeyResult.createResultAssembler( this, creationState ); } @Override @@ -95,7 +93,7 @@ protected ImmediateCollectionInitializerData createInitializerData(RowProcessing protected void forEachSubInitializer(BiConsumer, RowProcessingState> consumer, InitializerData data) { super.forEachSubInitializer( consumer, data ); if ( collectionValueKeyResultAssembler != null ) { - final Initializer initializer = collectionValueKeyResultAssembler.getInitializer(); + final var initializer = collectionValueKeyResultAssembler.getInitializer(); if ( initializer != null ) { consumer.accept( initializer, data.getRowProcessingState() ); } @@ -129,11 +127,11 @@ public void resolveState(Data data) { if ( collectionValueKeyResultAssembler != null ) { collectionValueKeyResultAssembler.resolveState( data.getRowProcessingState() ); } - final DomainResultAssembler indexAssembler = getIndexAssembler(); + final var indexAssembler = getIndexAssembler(); if ( indexAssembler != null ) { indexAssembler.resolveState( data.getRowProcessingState() ); } - final DomainResultAssembler elementAssembler = getElementAssembler(); + final var elementAssembler = getElementAssembler(); if ( elementAssembler != null ) { elementAssembler.resolveState( data.getRowProcessingState() ); } @@ -152,11 +150,13 @@ public void resolveFromPreviousRow(Data data) { */ private boolean resolveCollectionContentKey(Data data) { assert collectionValueKeyResultAssembler != null; - final RowProcessingState rowProcessingState = data.getRowProcessingState(); + final var rowProcessingState = data.getRowProcessingState(); //noinspection unchecked - final Initializer initializer = (Initializer) collectionValueKeyResultAssembler.getInitializer(); + final var initializer = + (Initializer) + collectionValueKeyResultAssembler.getInitializer(); if ( initializer != null ) { - InitializerData subData = initializer.getData( rowProcessingState ); + final var subData = initializer.getData( rowProcessingState ); initializer.resolveKey( subData ); if ( subData.getState() == State.MISSING ) { return true; @@ -176,13 +176,15 @@ private boolean resolveCollectionContentKey(Data data) { } private void resolveKeySubInitializers(Data data) { - final RowProcessingState rowProcessingState = data.getRowProcessingState(); - final DomainResultAssembler indexAssembler = getIndexAssembler(); - final Initializer indexInitializer; - if ( indexAssembler != null && ( indexInitializer = indexAssembler.getInitializer() ) != null ) { - indexInitializer.resolveKey( rowProcessingState ); + final var rowProcessingState = data.getRowProcessingState(); + final var indexAssembler = getIndexAssembler(); + if ( indexAssembler != null ) { + final var indexInitializer = indexAssembler.getInitializer(); + if ( indexInitializer != null ) { + indexInitializer.resolveKey( rowProcessingState ); + } } - final Initializer elementInitializer = getElementAssembler().getInitializer(); + final var elementInitializer = getElementAssembler().getInitializer(); if ( elementInitializer != null ) { elementInitializer.resolveKey( rowProcessingState ); } @@ -190,122 +192,117 @@ private void resolveKeySubInitializers(Data data) { @Override public void resolveInstance(Data data) { - if ( data.getState() != State.KEY_RESOLVED ) { - // already resolved - return; - } - - // Being a result initializer means that this collection initializer is for lazy loading, - // which has a very high chance that a collection resolved of the previous row is the same for the current row, - // so pass that flag as indicator whether to check previous row state. - // Note that we don't need to check previous rows in other cases, - // because the previous row checks are done by the owner of the collection initializer already. - resolveCollectionKey( data, isResultInitializer ); - if ( data.getState() != State.KEY_RESOLVED ) { - return; - } - - data.setState( State.RESOLVED ); - data.responsibility = null; + if ( data.getState() == State.KEY_RESOLVED ) {// Being a result initializer means that this collection initializer is for lazy loading, + // which has a very high chance that a collection resolved of the previous row is the same for the current row, + // so pass that flag as indicator whether to check previous row state. + // Note that we don't need to check previous rows in other cases, + // because the previous row checks are done by the owner of the collection initializer already. + resolveCollectionKey( data, isResultInitializer ); + if ( data.getState() == State.KEY_RESOLVED ) { + data.setState( State.RESOLVED ); + data.responsibility = null; + + // determine the PersistentCollection instance to use and whether + // we (this initializer) is responsible for loading its state + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // First, look for a LoadingCollectionEntry + final RowProcessingState rowProcessingState = data.getRowProcessingState(); + final SharedSessionContractImplementor session = rowProcessingState.getSession(); + final PersistenceContext persistenceContext = session.getPersistenceContextInternal(); + final CollectionKey collectionKey = data.collectionKey; + assert collectionKey != null; + final LoadingCollectionEntry existingLoadingEntry = persistenceContext.getLoadContexts() + .findLoadingCollectionEntry( collectionKey ); + final PersistentCollection existing; + final PersistentCollection existingUnowned; + if ( existingLoadingEntry != null ) { + data.setCollectionInstance( existingLoadingEntry.getCollectionInstance() ); + + if ( existingLoadingEntry.getInitializer() == this ) { + assert !data.shallowCached; + // we are responsible for loading the collection values + data.responsibility = (LoadingCollectionEntryImpl) existingLoadingEntry; + } + else { + // the entity is already being loaded elsewhere + data.setState( State.INITIALIZED ); + } + } + else if ( (existing = persistenceContext.getCollection( collectionKey )) != null ) { + data.setCollectionInstance( existing ); - // determine the PersistentCollection instance to use and whether - // we (this initializer) is responsible for loading its state - - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // First, look for a LoadingCollectionEntry - final RowProcessingState rowProcessingState = data.getRowProcessingState(); - final SharedSessionContractImplementor session = rowProcessingState.getSession(); - final PersistenceContext persistenceContext = session.getPersistenceContextInternal(); - final CollectionKey collectionKey = data.collectionKey; - assert collectionKey != null; - final LoadingCollectionEntry existingLoadingEntry = persistenceContext.getLoadContexts() - .findLoadingCollectionEntry( collectionKey ); - final PersistentCollection existing; - final PersistentCollection existingUnowned; - if ( existingLoadingEntry != null ) { - data.setCollectionInstance( existingLoadingEntry.getCollectionInstance() ); - - if ( existingLoadingEntry.getInitializer() == this ) { - assert !data.shallowCached; - // we are responsible for loading the collection values - data.responsibility = (LoadingCollectionEntryImpl) existingLoadingEntry; - } - else { - // the entity is already being loaded elsewhere - data.setState( State.INITIALIZED ); - } - } - else if ( ( existing = persistenceContext.getCollection( collectionKey ) ) != null ) { - data.setCollectionInstance( existing ); + // we found the corresponding collection instance on the Session. If + // it is already initialized we have nothing to do - // we found the corresponding collection instance on the Session. If - // it is already initialized we have nothing to do + if ( existing.wasInitialized() ) { + data.setState( State.INITIALIZED ); + } + else if ( !data.shallowCached ) { + takeResponsibility( data ); + } + } + else if ( (existingUnowned = persistenceContext.useUnownedCollection( collectionKey )) != null ) { + data.setCollectionInstance( existingUnowned ); - if ( existing.wasInitialized() ) { - data.setState( State.INITIALIZED ); - } - else if ( !data.shallowCached ) { - takeResponsibility( data ); - } - } - else if ( ( existingUnowned = persistenceContext.useUnownedCollection( collectionKey ) ) != null ) { - data.setCollectionInstance( existingUnowned ); + // we found the corresponding collection instance as unowned on the Session. If + // it is already initialized we have nothing to do - // we found the corresponding collection instance as unowned on the Session. If - // it is already initialized we have nothing to do + if ( existingUnowned.wasInitialized() ) { + data.setState( State.INITIALIZED ); + } + else if ( !data.shallowCached ) { + takeResponsibility( data ); + } + } + else { + final var collectionDescriptor = getCollectionAttributeMapping().getCollectionDescriptor(); + final var collectionSemantics = collectionDescriptor.getCollectionSemantics(); + final var persistentCollection = + collectionSemantics.instantiateWrapper( + collectionKey.getKey(), + getInitializingCollectionDescriptor(), + session + ); + data.setCollectionInstance( persistentCollection ); + + if ( owningEntityInitializer != null ) { + final Object targetInstance = + owningEntityInitializer.getTargetInstance( rowProcessingState ); + assert targetInstance != null; + data.getCollectionInstance().setOwner( targetInstance ); + } - if ( existingUnowned.wasInitialized() ) { - data.setState( State.INITIALIZED ); - } - else if ( !data.shallowCached ) { - takeResponsibility( data ); - } - } - else { - final CollectionPersister collectionDescriptor = getCollectionAttributeMapping().getCollectionDescriptor(); - final CollectionSemantics collectionSemantics = collectionDescriptor.getCollectionSemantics(); - final PersistentCollection persistentCollection = collectionSemantics.instantiateWrapper( - collectionKey.getKey(), - getInitializingCollectionDescriptor(), - session - ); - data.setCollectionInstance( persistentCollection ); - - if ( owningEntityInitializer != null ) { - assert owningEntityInitializer.getTargetInstance( rowProcessingState ) != null; - data.getCollectionInstance().setOwner( owningEntityInitializer.getTargetInstance( rowProcessingState ) ); - } + persistenceContext.addUninitializedCollection( + collectionDescriptor, + persistentCollection, + collectionKey.getKey() + ); - persistenceContext.addUninitializedCollection( - collectionDescriptor, - persistentCollection, - collectionKey.getKey() - ); + if ( !data.shallowCached ) { + takeResponsibility( data ); + } + } - if ( !data.shallowCached ) { - takeResponsibility( data ); + if ( data.shallowCached ) { + assert data.responsibility == null; + initializeShallowCached( data ); + } } } - - if ( data.shallowCached ) { - assert data.responsibility == null; - initializeShallowCached( data ); - } } protected void initializeShallowCached(Data data) { assert data.shallowCached; - final PersistenceContext persistenceContext = data.getRowProcessingState().getSession() - .getPersistenceContextInternal(); // If this is a query cache hit with the shallow query cache layout, // we have to lazy load the collection instead - final PersistentCollection collectionInstance = data.getCollectionInstance(); + final var collectionInstance = data.getCollectionInstance(); assert collectionInstance != null; collectionInstance.forceInitialization(); - if ( collectionAttributeMapping.getCollectionDescriptor() - .getCollectionSemantics() - .getCollectionClassification() == CollectionClassification.ARRAY ) { - persistenceContext.addCollectionHolder( collectionInstance ); + if ( collectionAttributeMapping.getCollectionDescriptor().isArray()) { + data.getRowProcessingState().getSession() + .getPersistenceContextInternal() + .addCollectionHolder( collectionInstance ); } data.setState( State.INITIALIZED ); initializeSubInstancesFromParent( data ); @@ -323,89 +320,78 @@ public void resolveInstance(Object instance, Data data) { assert data.getState() == State.UNINITIALIZED || instance == data.getCollectionInstance(); if ( instance == null ) { setMissing( data ); - return; - } - final RowProcessingState rowProcessingState = data.getRowProcessingState(); - final PersistentCollection persistentCollection; - // Check if the given instance is different from the previous row state to avoid creating CollectionKey - if ( data.getCollectionInstance() != instance ) { - final PersistenceContext persistenceContext = rowProcessingState.getSession().getPersistenceContextInternal(); - if ( collectionAttributeMapping.getCollectionDescriptor() - .getCollectionSemantics() - .getCollectionClassification() == CollectionClassification.ARRAY ) { - persistentCollection = persistenceContext.getCollectionHolder( instance ); - } - else { - persistentCollection = (PersistentCollection) instance; - } - data.collectionKeyValue = persistentCollection.getKey(); - resolveCollectionKey( data, false ); - data.setCollectionInstance( persistentCollection ); - data.responsibility = null; } else { - persistentCollection = (PersistentCollection) instance; - } - data.collectionValueKey = null; - if ( persistentCollection.wasInitialized() ) { - data.setState( State.INITIALIZED ); - if ( data.shallowCached ) { - initializeShallowCached( data ); + final var rowProcessingState = data.getRowProcessingState(); + final PersistentCollection collection; + // Check if the given instance is different from the previous row state to avoid creating CollectionKey + if ( data.getCollectionInstance() != instance ) { + collection = getCollection( data, instance ); + data.collectionKeyValue = collection.getKey(); + resolveCollectionKey( data, false ); + data.setCollectionInstance( collection ); + data.responsibility = null; } else { - resolveInstanceSubInitializers( data ); + collection = (PersistentCollection) instance; } - if ( rowProcessingState.needsResolveState() ) { - // Resolve the state of the identifier if result caching is enabled and this is not a query cache hit - if ( collectionKeyResultAssembler != null ) { - collectionKeyResultAssembler.resolveState( rowProcessingState ); + data.collectionValueKey = null; + if ( collection.wasInitialized() ) { + data.setState( State.INITIALIZED ); + if ( data.shallowCached ) { + initializeShallowCached( data ); + } + else { + resolveInstanceSubInitializers( data ); } - if ( !getInitializingCollectionDescriptor().useShallowQueryCacheLayout() ) { - if ( collectionValueKeyResultAssembler != null ) { - collectionValueKeyResultAssembler.resolveState( rowProcessingState ); + if ( rowProcessingState.needsResolveState() ) { + // Resolve the state of the identifier if result caching is enabled and this is not a query cache hit + if ( collectionKeyResultAssembler != null ) { + collectionKeyResultAssembler.resolveState( rowProcessingState ); + } + if ( !getInitializingCollectionDescriptor().useShallowQueryCacheLayout() ) { + if ( collectionValueKeyResultAssembler != null ) { + collectionValueKeyResultAssembler.resolveState( rowProcessingState ); + } + resolveCollectionContentState( rowProcessingState ); } - resolveCollectionContentState( rowProcessingState ); } } - } - else { - if ( data.shallowCached ) { - data.setState( State.INITIALIZED ); - initializeShallowCached( data ); - } else { - data.setState( State.RESOLVED ); - final boolean rowContainsCollectionContent; - if ( collectionValueKeyResultAssembler != null ) { - rowContainsCollectionContent = resolveCollectionContentKey( data ); + if ( data.shallowCached ) { + data.setState( State.INITIALIZED ); + initializeShallowCached( data ); } else { - rowContainsCollectionContent = true; - } - if ( data.responsibility == null ) { - final LoadingCollectionEntry existingLoadingEntry = rowProcessingState.getSession() - .getPersistenceContextInternal() - .getLoadContexts() - .findLoadingCollectionEntry( data.collectionKey ); - if ( existingLoadingEntry != null ) { - if ( existingLoadingEntry.getInitializer() == this ) { - // we are responsible for loading the collection values - data.responsibility = (LoadingCollectionEntryImpl) existingLoadingEntry; + data.setState( State.RESOLVED ); + final boolean rowContainsCollectionContent = + collectionValueKeyResultAssembler == null + || resolveCollectionContentKey( data ); + if ( data.responsibility == null ) { + final var existingLoadingEntry = + rowProcessingState.getSession().getPersistenceContextInternal() + .getLoadContexts().findLoadingCollectionEntry( data.collectionKey ); + if ( existingLoadingEntry != null ) { + if ( existingLoadingEntry.getInitializer() == this ) { + // we are responsible for loading the collection values + data.responsibility = (LoadingCollectionEntryImpl) existingLoadingEntry; + } + else { + // the collection is already being loaded elsewhere + data.setState( State.INITIALIZED ); + if ( rowContainsCollectionContent && rowProcessingState.needsResolveState() + && !getInitializingCollectionDescriptor().useShallowQueryCacheLayout() ) { + // Resolve the state of the content if result caching is enabled, + // and this is not a query cache hit, and the collection doesn't + // use a shallow query cache layout + resolveCollectionContentState( rowProcessingState ); + } + } } else { - // the collection is already being loaded elsewhere - data.setState( State.INITIALIZED ); - if ( rowContainsCollectionContent && rowProcessingState.needsResolveState() - && !getInitializingCollectionDescriptor().useShallowQueryCacheLayout() ) { - // Resolve the state of the content if result caching is enabled and this is not a query cache hit - // and the collection doesn't use a shallow query cache layout - resolveCollectionContentState( rowProcessingState ); - } + takeResponsibility( data ); } } - else { - takeResponsibility( data ); - } } } } @@ -414,7 +400,7 @@ public void resolveInstance(Object instance, Data data) { protected abstract void resolveInstanceSubInitializers(Data data); private void resolveCollectionContentState(RowProcessingState rowProcessingState) { - final DomainResultAssembler indexAssembler = getIndexAssembler(); + final var indexAssembler = getIndexAssembler(); if ( indexAssembler != null ) { indexAssembler.resolveState( rowProcessingState ); } @@ -422,36 +408,35 @@ private void resolveCollectionContentState(RowProcessingState rowProcessingState } protected void takeResponsibility(Data data) { - data.responsibility = new LoadingCollectionEntryImpl( - getCollectionAttributeMapping().getCollectionDescriptor(), - this, - data.collectionKey.getKey(), - data.getCollectionInstance() - ); - data.getRowProcessingState().getJdbcValuesSourceProcessingState().registerLoadingCollection( - data.collectionKey, - data.responsibility - ); + data.responsibility = + new LoadingCollectionEntryImpl( + getCollectionAttributeMapping().getCollectionDescriptor(), + this, + data.collectionKey.getKey(), + data.getCollectionInstance() + ); + data.getRowProcessingState().getJdbcValuesSourceProcessingState() + .registerLoadingCollection( data.collectionKey, data.responsibility ); } @Override public void initializeInstance(Data data) { - if ( data.getState() != State.RESOLVED || data.responsibility == null ) { - return; - } - data.setState( State.INITIALIZED ); + if ( data.getState() == State.RESOLVED && data.responsibility != null ) { + data.setState( State.INITIALIZED ); - if ( data.collectionValueKey == null && collectionValueKeyResultAssembler != null ) { - final Initializer initializer = collectionValueKeyResultAssembler.getInitializer(); - if ( initializer != null ) { - data.collectionValueKey = collectionValueKeyResultAssembler.assemble( data.getRowProcessingState() ); + if ( data.collectionValueKey == null && collectionValueKeyResultAssembler != null ) { + final var initializer = collectionValueKeyResultAssembler.getInitializer(); + if ( initializer != null ) { + data.collectionValueKey = collectionValueKeyResultAssembler.assemble( + data.getRowProcessingState() ); + } } - } - // the RHS key value of the association - determines if the row contains an element of the initializing collection - if ( collectionValueKeyResultAssembler == null || data.collectionValueKey != null ) { - // the row contains an element in the collection... - data.responsibility.load( data, this ); + // the RHS key value of the association - determines if the row contains an element of the initializing collection + if ( collectionValueKeyResultAssembler == null || data.collectionValueKey != null ) { + // the row contains an element in the collection... + data.responsibility.load( data, this ); + } } } @@ -464,15 +449,9 @@ public void initializeInstanceFromParent(Object parentInstance, Data data) { @Override public boolean hasLazySubInitializers() { - final DomainResultAssembler indexAssembler = getIndexAssembler(); - if ( indexAssembler != null ) { - final Initializer initializer = indexAssembler.getInitializer(); - if ( initializer != null && ( !initializer.isEager() || initializer.hasLazySubInitializers() ) ) { - return true; - } - } - final Initializer initializer = getElementAssembler().getInitializer(); - return initializer != null && ( !initializer.isEager() || initializer.hasLazySubInitializers() ); + final var indexAssembler = getIndexAssembler(); + return indexAssembler != null && indexAssembler.hasLazySubInitializers() + || getElementAssembler().hasLazySubInitializers(); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/AbstractNonJoinCollectionInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/AbstractNonJoinCollectionInitializer.java index b2aea7947a5c..82e88f3469fc 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/AbstractNonJoinCollectionInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/AbstractNonJoinCollectionInitializer.java @@ -4,21 +4,11 @@ */ package org.hibernate.sql.results.graph.collection.internal; -import org.hibernate.collection.spi.CollectionSemantics; -import org.hibernate.collection.spi.PersistentCollection; -import org.hibernate.engine.spi.CollectionKey; -import org.hibernate.engine.spi.PersistenceContext; -import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.metamodel.CollectionClassification; import org.hibernate.metamodel.mapping.PluralAttributeMapping; -import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.results.graph.AssemblerCreationState; import org.hibernate.sql.results.graph.DomainResult; -import org.hibernate.sql.results.graph.InitializerData; import org.hibernate.sql.results.graph.InitializerParent; -import org.hibernate.sql.results.graph.collection.LoadingCollectionEntry; -import org.hibernate.sql.results.jdbc.spi.RowProcessingState; import org.checkerframework.checker.nullness.qual.Nullable; @@ -48,82 +38,69 @@ public AbstractNonJoinCollectionInitializer( } protected void resolveInstance(Data data, boolean isEager) { - if ( data.getState() != State.KEY_RESOLVED ) { - // already resolved - return; - } - - resolveCollectionKey( data, false ); if ( data.getState() == State.KEY_RESOLVED ) { - assert owningEntityInitializer != null; - final RowProcessingState rowProcessingState = data.getRowProcessingState(); - // We can avoid processing further if the parent is already initialized, - // as the value produced by this initializer will never be used anyway. - final InitializerData owningEntityData = owningEntityInitializer.getData( rowProcessingState ); - if ( owningEntityData.getState() == State.INITIALIZED ) { - // It doesn't matter if it's eager or lazy, the collection object can not be referred to, - // so it doesn't make sense to create or initialize it - data.setState( State.MISSING ); - return; - } - // This initializer is done initializing, since this is only invoked for delayed or select initializers - data.setState( State.INITIALIZED ); - - final SharedSessionContractImplementor session = rowProcessingState.getSession(); - final PersistenceContext persistenceContext = session.getPersistenceContextInternal(); - final CollectionKey collectionKey = data.collectionKey; - assert collectionKey != null; - - final LoadingCollectionEntry loadingEntry = persistenceContext.getLoadContexts() - .findLoadingCollectionEntry( collectionKey ); - - if ( loadingEntry != null ) { - final PersistentCollection collectionInstance = loadingEntry.getCollectionInstance(); - data.setCollectionInstance( collectionInstance ); - if ( collectionInstance.getOwner() == null ) { - assert owningEntityInitializer.getTargetInstance( owningEntityData ) != null; - collectionInstance.setOwner( owningEntityInitializer.getTargetInstance( owningEntityData ) ); + resolveCollectionKey( data, false ); + if ( data.getState() == State.KEY_RESOLVED ) { + assert owningEntityInitializer != null; + final var rowProcessingState = data.getRowProcessingState(); + // We can avoid processing further if the parent is already initialized, + // as the value produced by this initializer will never be used anyway. + final var owningEntityData = owningEntityInitializer.getData( rowProcessingState ); + if ( owningEntityData.getState() == State.INITIALIZED ) { + // It doesn't matter if it's eager or lazy, the collection object can not be referred to, + // so it doesn't make sense to create or initialize it + data.setState( State.MISSING ); } - return; - } - - final PersistentCollection existing = persistenceContext.getCollection( collectionKey ); - - if ( existing != null ) { - data.setCollectionInstance( existing ); - if ( existing.getOwner() == null ) { - assert owningEntityInitializer.getTargetInstance( owningEntityData ) != null; - existing.setOwner( owningEntityInitializer.getTargetInstance( owningEntityData ) ); + else { + // This initializer is done initializing, since this is only invoked for delayed or select initializers + data.setState( State.INITIALIZED ); + + final var session = rowProcessingState.getSession(); + final var persistenceContext = session.getPersistenceContextInternal(); + final var collectionKey = data.collectionKey; + assert collectionKey != null; + + final var loadingEntry = + persistenceContext.getLoadContexts() + .findLoadingCollectionEntry( collectionKey ); + if ( loadingEntry != null ) { + final var collectionInstance = loadingEntry.getCollectionInstance(); + data.setCollectionInstance( collectionInstance ); + if ( collectionInstance.getOwner() == null ) { + assert owningEntityInitializer.getTargetInstance( owningEntityData ) != null; + collectionInstance.setOwner( + owningEntityInitializer.getTargetInstance( owningEntityData ) ); + } + } + else { + final var existing = persistenceContext.getCollection( collectionKey ); + if ( existing != null ) { + data.setCollectionInstance( existing ); + if ( existing.getOwner() == null ) { + assert owningEntityInitializer.getTargetInstance( owningEntityData ) != null; + existing.setOwner( owningEntityInitializer.getTargetInstance( owningEntityData ) ); + } + } + else { + final var collectionDescriptor = collectionAttributeMapping.getCollectionDescriptor(); + final Object key = collectionKey.getKey(); + final var collection = + collectionDescriptor.getCollectionSemantics() + .instantiateWrapper( key, collectionDescriptor, session ); + data.setCollectionInstance( collection ); + final Object targetInstance = owningEntityInitializer.getTargetInstance( owningEntityData ); + assert targetInstance != null; + collection.setOwner( targetInstance ); + persistenceContext.addUninitializedCollection( collectionDescriptor, collection, key ); + if ( isEager ) { + persistenceContext.addNonLazyCollection( collection ); + } + if ( collectionDescriptor.isArray() ) { + persistenceContext.addCollectionHolder( collection ); + } + } + } } - return; - } - - final CollectionPersister collectionDescriptor = collectionAttributeMapping.getCollectionDescriptor(); - final CollectionSemantics collectionSemantics = collectionDescriptor.getCollectionSemantics(); - final Object key = collectionKey.getKey(); - - final PersistentCollection persistentCollection = collectionSemantics.instantiateWrapper( - key, - collectionDescriptor, - session - ); - data.setCollectionInstance( persistentCollection ); - - assert owningEntityInitializer.getTargetInstance( owningEntityData ) != null; - persistentCollection.setOwner( owningEntityInitializer.getTargetInstance( owningEntityData ) ); - - persistenceContext.addUninitializedCollection( - collectionDescriptor, - persistentCollection, - key - ); - - if ( isEager ) { - persistenceContext.addNonLazyCollection( persistentCollection ); - } - - if ( collectionSemantics.getCollectionClassification() == CollectionClassification.ARRAY ) { - persistenceContext.addCollectionHolder( persistentCollection ); } } } @@ -133,17 +110,8 @@ protected void resolveInstance(Object instance, Data data, boolean isEager) { setMissing( data ); } else { - final RowProcessingState rowProcessingState = data.getRowProcessingState(); - final PersistenceContext persistenceContext = rowProcessingState.getSession().getPersistenceContextInternal(); - final PersistentCollection persistentCollection; - if ( collectionAttributeMapping.getCollectionDescriptor() - .getCollectionSemantics() - .getCollectionClassification() == CollectionClassification.ARRAY ) { - persistentCollection = persistenceContext.getCollectionHolder( instance ); - } - else { - persistentCollection = (PersistentCollection) instance; - } + final var rowProcessingState = data.getRowProcessingState(); + final var persistentCollection = getCollection( data, instance ); // resolving the collection key seems unnecessary // collectionKeyValue = persistentCollection.getKey(); // resolveCollectionKey( rowProcessingState, false ); @@ -151,10 +119,11 @@ protected void resolveInstance(Object instance, Data data, boolean isEager) { // This initializer is done initializing, since this is only invoked for delayed or select initializers data.setState( State.INITIALIZED ); if ( isEager && !persistentCollection.wasInitialized() ) { - persistenceContext.addNonLazyCollection( persistentCollection ); + rowProcessingState.getSession().getPersistenceContextInternal() + .addNonLazyCollection( persistentCollection ); } if ( collectionKeyResultAssembler != null && rowProcessingState.needsResolveState() ) { - // Resolve the state of the identifier if result caching is enabled and this is not a query cache hit + // Resolve the state of the identifier if result caching is enabled, and this is not a query cache hit collectionKeyResultAssembler.resolveState( rowProcessingState ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/ArrayInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/ArrayInitializer.java index 15ea69534c33..d6a45d87c071 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/ArrayInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/ArrayInitializer.java @@ -4,15 +4,12 @@ */ package org.hibernate.sql.results.graph.collection.internal; -import java.lang.reflect.Array; -import java.util.Iterator; import java.util.List; import java.util.function.BiConsumer; import org.hibernate.HibernateException; import org.hibernate.LockMode; import org.hibernate.collection.spi.PersistentArrayHolder; -import org.hibernate.internal.log.LoggingHelper; import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.results.graph.AssemblerCreationState; @@ -26,6 +23,9 @@ import org.checkerframework.checker.nullness.qual.Nullable; +import static java.lang.reflect.Array.get; +import static org.hibernate.internal.log.LoggingHelper.toLoggableString; + /** * @author Chris Cranford */ @@ -57,15 +57,15 @@ public ArrayInitializer( creationState ); //noinspection unchecked - this.listIndexAssembler = (DomainResultAssembler) listIndexFetch.createAssembler( this, creationState ); - this.elementAssembler = elementFetch.createAssembler( this, creationState ); - this.indexBase = getCollectionAttributeMapping().getIndexMetadata().getListIndexBase(); + listIndexAssembler = (DomainResultAssembler) listIndexFetch.createAssembler( this, creationState ); + elementAssembler = elementFetch.createAssembler( this, creationState ); + indexBase = getCollectionAttributeMapping().getIndexMetadata().getListIndexBase(); } @Override protected void forEachSubInitializer(BiConsumer, RowProcessingState> consumer, InitializerData data) { super.forEachSubInitializer( consumer, data ); - final Initializer initializer = elementAssembler.getInitializer(); + final var initializer = elementAssembler.getInitializer(); if ( initializer != null ) { consumer.accept( initializer, data.getRowProcessingState() ); } @@ -78,7 +78,7 @@ protected void forEachSubInitializer(BiConsumer, RowProcessingSta @Override protected void readCollectionRow(ImmediateCollectionInitializerData data, List loadingState) { - final RowProcessingState rowProcessingState = data.getRowProcessingState(); + final var rowProcessingState = data.getRowProcessingState(); final Integer indexValue = listIndexAssembler.assemble( rowProcessingState ); if ( indexValue == null ) { throw new HibernateException( "Illegal null value for array index encountered while reading: " @@ -104,21 +104,23 @@ protected void readCollectionRow(ImmediateCollectionInitializerData data, List initializer = elementAssembler.getInitializer(); + final var initializer = elementAssembler.getInitializer(); if ( initializer != null ) { - final RowProcessingState rowProcessingState = data.getRowProcessingState(); - final Iterator iter = getCollectionInstance( data ).elements(); + final var rowProcessingState = data.getRowProcessingState(); + final var iter = getCollectionInstance( data ).elements(); while ( iter.hasNext() ) { initializer.initializeInstanceFromParent( iter.next(), rowProcessingState ); } @@ -127,17 +129,17 @@ protected void initializeSubInstancesFromParent(ImmediateCollectionInitializerDa @Override protected void resolveInstanceSubInitializers(ImmediateCollectionInitializerData data) { - final Initializer initializer = elementAssembler.getInitializer(); + final var initializer = elementAssembler.getInitializer(); if ( initializer != null ) { - final RowProcessingState rowProcessingState = data.getRowProcessingState(); + final var rowProcessingState = data.getRowProcessingState(); Integer index = listIndexAssembler.assemble( rowProcessingState ); if ( index != null ) { - final PersistentArrayHolder arrayHolder = getCollectionInstance( data ); + final var arrayHolder = getCollectionInstance( data ); assert arrayHolder != null; if ( indexBase != 0 ) { index -= indexBase; } - initializer.resolveInstance( Array.get( arrayHolder.getArray(), index ), rowProcessingState ); + initializer.resolveInstance( get( arrayHolder.getArray(), index ), rowProcessingState ); } } } @@ -154,6 +156,6 @@ public DomainResultAssembler getElementAssembler() { @Override public String toString() { - return "ArrayInitializer{" + LoggingHelper.toLoggableString( getNavigablePath() ) + ")"; + return "ArrayInitializer{" + toLoggableString( getNavigablePath() ) + ")"; } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/BagInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/BagInitializer.java index fb6b0e7a31c3..d60520480d13 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/BagInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/BagInitializer.java @@ -7,11 +7,10 @@ import java.util.List; import java.util.function.BiConsumer; +import org.hibernate.AssertionFailure; import org.hibernate.LockMode; import org.hibernate.collection.spi.PersistentBag; -import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.collection.spi.PersistentIdentifierBag; -import org.hibernate.internal.log.LoggingHelper; import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.results.graph.AssemblerCreationState; @@ -25,6 +24,8 @@ import org.checkerframework.checker.nullness.qual.Nullable; +import static org.hibernate.internal.log.LoggingHelper.toLoggableString; + /** * Initializer for both {@link PersistentBag} and {@link PersistentIdentifierBag} * collections @@ -57,16 +58,17 @@ public BagInitializer( isResultInitializer, creationState ); - this.elementAssembler = elementFetch.createAssembler( this, creationState ); - this.collectionIdAssembler = collectionIdFetch == null - ? null - : collectionIdFetch.createAssembler( this, creationState ); + elementAssembler = elementFetch.createAssembler( this, creationState ); + collectionIdAssembler = + collectionIdFetch == null + ? null + : collectionIdFetch.createAssembler( this, creationState ); } @Override protected void forEachSubInitializer(BiConsumer, RowProcessingState> consumer, InitializerData data) { super.forEachSubInitializer( consumer, data ); - final Initializer initializer = elementAssembler.getInitializer(); + final var initializer = elementAssembler.getInitializer(); if ( initializer != null ) { consumer.accept( initializer, data.getRowProcessingState() ); } @@ -74,19 +76,16 @@ protected void forEachSubInitializer(BiConsumer, RowProcessingSta @Override protected void readCollectionRow(ImmediateCollectionInitializerData data, List loadingState) { - final RowProcessingState rowProcessingState = data.getRowProcessingState(); + final var rowProcessingState = data.getRowProcessingState(); if ( collectionIdAssembler != null ) { final Object collectionId = collectionIdAssembler.assemble( rowProcessingState ); - if ( collectionId == null ) { - return; - } - final Object element = elementAssembler.assemble( rowProcessingState ); - if ( element == null ) { - // If element is null, then NotFoundAction must be IGNORE - return; + if ( collectionId != null ) { + final Object element = elementAssembler.assemble( rowProcessingState ); + if ( element != null ) { + loadingState.add( new Object[] {collectionId, element} ); + } + // otherwise, if element is null, then NotFoundAction must be IGNORE } - - loadingState.add( new Object[]{ collectionId, element } ); } else { final Object element = elementAssembler.assemble( rowProcessingState ); @@ -99,27 +98,30 @@ protected void readCollectionRow(ImmediateCollectionInitializerData data, List initializer = elementAssembler.getInitializer(); + final var initializer = elementAssembler.getInitializer(); if ( initializer != null ) { - final RowProcessingState rowProcessingState = data.getRowProcessingState(); - final PersistentCollection persistentCollection = getCollectionInstance( data ); + final var rowProcessingState = data.getRowProcessingState(); + final var persistentCollection = getCollectionInstance( data ); assert persistentCollection != null; - if ( persistentCollection instanceof PersistentBag ) { - for ( Object element : ( (PersistentBag) persistentCollection ) ) { + if ( persistentCollection instanceof PersistentBag bag ) { + for ( Object element : bag ) { initializer.initializeInstanceFromParent( element, rowProcessingState ); } } - else { - for ( Object element : ( (PersistentIdentifierBag) persistentCollection ) ) { + else if ( persistentCollection instanceof PersistentIdentifierBag idbag ) { + for ( Object element : idbag ) { initializer.initializeInstanceFromParent( element, rowProcessingState ); } } + else { + throw new AssertionFailure( "Unexpected collection type" ); + } } } @Override protected void resolveInstanceSubInitializers(ImmediateCollectionInitializerData data) { - final Initializer initializer = elementAssembler.getInitializer(); + final var initializer = elementAssembler.getInitializer(); if ( initializer != null ) { initializer.resolveKey( data.getRowProcessingState() ); } @@ -137,6 +139,6 @@ public DomainResultAssembler getElementAssembler() { @Override public String toString() { - return "BagInitializer(" + LoggingHelper.toLoggableString( getNavigablePath() ) + ")"; + return "BagInitializer(" + toLoggableString( getNavigablePath() ) + ")"; } } 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 79d911f5d72a..9d2fb738119a 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 @@ -4,13 +4,14 @@ */ package org.hibernate.sql.results.graph.collection.internal; -import org.hibernate.internal.log.LoggingHelper; import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.results.graph.AssemblerCreationState; import org.hibernate.sql.results.graph.DomainResult; import org.hibernate.sql.results.graph.InitializerParent; +import static org.hibernate.internal.log.LoggingHelper.toLoggableString; + /** * @author Steve Ebersole */ @@ -48,7 +49,7 @@ public boolean hasLazySubInitializers() { @Override public String toString() { - return "DelayedCollectionInitializer(" + LoggingHelper.toLoggableString( getNavigablePath() ) + ")"; + return "DelayedCollectionInitializer(" + toLoggableString( getNavigablePath() ) + ")"; } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/ListInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/ListInitializer.java index 78382cf1de83..e1f3a0aed7b5 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/ListInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/ListInitializer.java @@ -10,7 +10,6 @@ import org.hibernate.HibernateException; import org.hibernate.LockMode; import org.hibernate.collection.spi.PersistentList; -import org.hibernate.internal.log.LoggingHelper; import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.results.graph.AssemblerCreationState; @@ -24,6 +23,8 @@ import org.checkerframework.checker.nullness.qual.Nullable; +import static org.hibernate.internal.log.LoggingHelper.toLoggableString; + /** * CollectionInitializer for PersistentList loading * @@ -58,15 +59,15 @@ public ListInitializer( creationState ); //noinspection unchecked - this.listIndexAssembler = (DomainResultAssembler) listIndexFetch.createAssembler( this, creationState ); - this.elementAssembler = elementFetch.createAssembler( this, creationState ); - this.listIndexBase = attributeMapping.getIndexMetadata().getListIndexBase(); + listIndexAssembler = (DomainResultAssembler) listIndexFetch.createAssembler( this, creationState ); + elementAssembler = elementFetch.createAssembler( this, creationState ); + listIndexBase = attributeMapping.getIndexMetadata().getListIndexBase(); } @Override protected void forEachSubInitializer(BiConsumer, RowProcessingState> consumer, InitializerData data) { super.forEachSubInitializer( consumer, data ); - final Initializer initializer = elementAssembler.getInitializer(); + final var initializer = elementAssembler.getInitializer(); if ( initializer != null ) { consumer.accept( initializer, data.getRowProcessingState() ); } @@ -79,36 +80,32 @@ protected void forEachSubInitializer(BiConsumer, RowProcessingSta @Override protected void readCollectionRow(ImmediateCollectionInitializerData data, List loadingState) { - final RowProcessingState rowProcessingState = data.getRowProcessingState(); + final var rowProcessingState = data.getRowProcessingState(); final Integer indexValue = listIndexAssembler.assemble( rowProcessingState ); if ( indexValue == null ) { throw new HibernateException( "Illegal null value for list index encountered while reading: " + getCollectionAttributeMapping().getNavigableRole() ); } final Object element = elementAssembler.assemble( rowProcessingState ); - if ( element == null ) { - // If element is null, then NotFoundAction must be IGNORE - return; - } - int index = indexValue; - - if ( listIndexBase != 0 ) { - index -= listIndexBase; - } - - for ( int i = loadingState.size(); i <= index; ++i ) { - loadingState.add( i, null ); + if ( element != null ) { + int index = indexValue; + if ( listIndexBase != 0 ) { + index -= listIndexBase; + } + for ( int i = loadingState.size(); i <= index; ++i ) { + loadingState.add( i, null ); + } + loadingState.set( index, element ); } - - loadingState.set( index, element ); + // else if the element is null, then NotFoundAction must be IGNORE } @Override protected void initializeSubInstancesFromParent(ImmediateCollectionInitializerData data) { - final Initializer initializer = elementAssembler.getInitializer(); + final var initializer = elementAssembler.getInitializer(); if ( initializer != null ) { - final RowProcessingState rowProcessingState = data.getRowProcessingState(); - final PersistentList list = getCollectionInstance( data ); + final var rowProcessingState = data.getRowProcessingState(); + final var list = getCollectionInstance( data ); assert list != null; for ( Object element : list ) { initializer.initializeInstanceFromParent( element, rowProcessingState ); @@ -118,12 +115,12 @@ protected void initializeSubInstancesFromParent(ImmediateCollectionInitializerDa @Override protected void resolveInstanceSubInitializers(ImmediateCollectionInitializerData data) { - final Initializer initializer = elementAssembler.getInitializer(); + final var initializer = elementAssembler.getInitializer(); if ( initializer != null ) { - final RowProcessingState rowProcessingState = data.getRowProcessingState(); + final var rowProcessingState = data.getRowProcessingState(); Integer index = listIndexAssembler.assemble( rowProcessingState ); if ( index != null ) { - final PersistentList list = getCollectionInstance( data ); + final var list = getCollectionInstance( data ); assert list != null; if ( listIndexBase != 0 ) { index -= listIndexBase; @@ -145,6 +142,6 @@ public DomainResultAssembler getElementAssembler() { @Override public String toString() { - return "ListInitializer(" + LoggingHelper.toLoggableString( getNavigablePath() ) + ")"; + return "ListInitializer(" + toLoggableString( getNavigablePath() ) + ")"; } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/MapInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/MapInitializer.java index 75874bd1ad5c..08034a54de30 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/MapInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/MapInitializer.java @@ -5,12 +5,10 @@ package org.hibernate.sql.results.graph.collection.internal; import java.util.List; -import java.util.Map; import java.util.function.BiConsumer; import org.hibernate.LockMode; import org.hibernate.collection.spi.PersistentMap; -import org.hibernate.internal.log.LoggingHelper; import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.results.graph.AssemblerCreationState; @@ -24,6 +22,8 @@ import org.checkerframework.checker.nullness.qual.Nullable; +import static org.hibernate.internal.log.LoggingHelper.toLoggableString; + /** * Represents an immediate initialization of some sort (join, select, batch, sub-select) * of a persistent Map valued attribute. @@ -58,18 +58,18 @@ public MapInitializer( isResultInitializer, creationState ); - this.mapKeyAssembler = mapKeyFetch.createAssembler( this, creationState ); - this.mapValueAssembler = mapValueFetch.createAssembler( this, creationState ); + mapKeyAssembler = mapKeyFetch.createAssembler( this, creationState ); + mapValueAssembler = mapValueFetch.createAssembler( this, creationState ); } @Override protected void forEachSubInitializer(BiConsumer, RowProcessingState> consumer, InitializerData data) { super.forEachSubInitializer( consumer, data ); - final Initializer keyInitializer = mapKeyAssembler.getInitializer(); + final var keyInitializer = mapKeyAssembler.getInitializer(); if ( keyInitializer != null ) { consumer.accept( keyInitializer, data.getRowProcessingState() ); } - final Initializer valueInitializer = mapValueAssembler.getInitializer(); + final var valueInitializer = mapValueAssembler.getInitializer(); if ( valueInitializer != null ) { consumer.accept( valueInitializer, data.getRowProcessingState() ); } @@ -82,29 +82,27 @@ protected void forEachSubInitializer(BiConsumer, RowProcessingSta @Override protected void readCollectionRow(ImmediateCollectionInitializerData data, List loadingState) { - final RowProcessingState rowProcessingState = data.getRowProcessingState(); + final var rowProcessingState = data.getRowProcessingState(); final Object key = mapKeyAssembler.assemble( rowProcessingState ); - if ( key == null ) { - // If element is null, then NotFoundAction must be IGNORE - return; - } - final Object value = mapValueAssembler.assemble( rowProcessingState ); - if ( value == null ) { - // If element is null, then NotFoundAction must be IGNORE - return; + if ( key != null ) { + final Object value = mapValueAssembler.assemble( rowProcessingState ); + if ( value != null ) { + loadingState.add( new Object[] {key, value} ); + } + // else if the element is null, then NotFoundAction must be IGNORE } - loadingState.add( new Object[] { key, value } ); + // else if the key is null, then NotFoundAction must be IGNORE } @Override protected void initializeSubInstancesFromParent(ImmediateCollectionInitializerData data) { - final Initializer keyInitializer = mapKeyAssembler.getInitializer(); - final Initializer valueInitializer = mapValueAssembler.getInitializer(); + final var keyInitializer = mapKeyAssembler.getInitializer(); + final var valueInitializer = mapValueAssembler.getInitializer(); if ( keyInitializer != null || valueInitializer != null ) { - final RowProcessingState rowProcessingState = data.getRowProcessingState(); - final PersistentMap map = getCollectionInstance( data ); + final var rowProcessingState = data.getRowProcessingState(); + final var map = getCollectionInstance( data ); assert map != null; - for ( Map.Entry entry : map.entrySet() ) { + for ( var entry : map.entrySet() ) { if ( keyInitializer != null ) { keyInitializer.initializeInstanceFromParent( entry.getKey(), rowProcessingState ); } @@ -117,9 +115,9 @@ protected void initializeSubInstancesFromParent(ImmediateCollectionInitializerDa @Override protected void resolveInstanceSubInitializers(ImmediateCollectionInitializerData data) { - final Initializer keyInitializer = mapKeyAssembler.getInitializer(); - final Initializer valueInitializer = mapValueAssembler.getInitializer(); - final RowProcessingState rowProcessingState = data.getRowProcessingState(); + final var keyInitializer = mapKeyAssembler.getInitializer(); + final var valueInitializer = mapValueAssembler.getInitializer(); + final var rowProcessingState = data.getRowProcessingState(); if ( keyInitializer == null && valueInitializer != null ) { // For now, we only support resolving the value initializer instance when keys have no initializer, // though we could also support map keys with an initializer given that the initialized java type: @@ -156,6 +154,6 @@ public DomainResultAssembler getElementAssembler() { @Override public String toString() { - return "MapInitializer(" + LoggingHelper.toLoggableString( getNavigablePath() ) + ")"; + return "MapInitializer(" + toLoggableString( getNavigablePath() ) + ")"; } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/SelectEagerCollectionInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/SelectEagerCollectionInitializer.java index 64ed29d2729a..4d59266d8231 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/SelectEagerCollectionInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/SelectEagerCollectionInitializer.java @@ -4,9 +4,6 @@ */ package org.hibernate.sql.results.graph.collection.internal; -import org.hibernate.collection.spi.PersistentCollection; -import org.hibernate.internal.log.LoggingHelper; -import org.hibernate.metamodel.CollectionClassification; import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.results.graph.AssemblerCreationState; @@ -15,10 +12,13 @@ import org.checkerframework.checker.nullness.qual.Nullable; +import static org.hibernate.internal.log.LoggingHelper.toLoggableString; + /** * @author Andrea Boriero */ -public class SelectEagerCollectionInitializer extends AbstractNonJoinCollectionInitializer { +public class SelectEagerCollectionInitializer + extends AbstractNonJoinCollectionInitializer { public SelectEagerCollectionInitializer( NavigablePath fetchedPath, @@ -46,16 +46,7 @@ public void initializeInstanceFromParent(Object parentInstance, CollectionInitia setMissing( data ); } else { - final PersistentCollection collection; - if ( collectionAttributeMapping.getCollectionDescriptor() - .getCollectionSemantics() - .getCollectionClassification() == CollectionClassification.ARRAY ) { - collection = data.getRowProcessingState().getSession().getPersistenceContextInternal() - .getCollectionHolder( instance ); - } - else { - collection = (PersistentCollection) instance; - } + final var collection = getCollection( data, instance ); data.setState( State.INITIALIZED ); data.setCollectionInstance( collection ); collection.forceInitialization(); @@ -64,6 +55,6 @@ public void initializeInstanceFromParent(Object parentInstance, CollectionInitia @Override public String toString() { - return "SelectEagerCollectionInitializer(" + LoggingHelper.toLoggableString( getNavigablePath() ) + ")"; + return "SelectEagerCollectionInitializer(" + toLoggableString( getNavigablePath() ) + ")"; } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/SetInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/SetInitializer.java index 9d3fea87edc8..a9d9163000a3 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/SetInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/SetInitializer.java @@ -9,7 +9,6 @@ import org.hibernate.LockMode; import org.hibernate.collection.spi.PersistentSet; -import org.hibernate.internal.log.LoggingHelper; import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.results.graph.AssemblerCreationState; @@ -23,6 +22,8 @@ import org.checkerframework.checker.nullness.qual.Nullable; +import static org.hibernate.internal.log.LoggingHelper.toLoggableString; + /** * @author Steve Ebersole */ @@ -56,7 +57,7 @@ public SetInitializer( @Override protected void forEachSubInitializer(BiConsumer, RowProcessingState> consumer, InitializerData data) { super.forEachSubInitializer( consumer, data ); - final Initializer initializer = elementAssembler.getInitializer(); + final var initializer = elementAssembler.getInitializer(); if ( initializer != null ) { consumer.accept( initializer, data.getRowProcessingState() ); } @@ -69,21 +70,20 @@ protected void forEachSubInitializer(BiConsumer, RowProcessingSta @Override protected void readCollectionRow(ImmediateCollectionInitializerData data, List loadingState) { - final RowProcessingState rowProcessingState = data.getRowProcessingState(); + final var rowProcessingState = data.getRowProcessingState(); final Object element = elementAssembler.assemble( rowProcessingState ); - if ( element == null ) { - // If element is null, then NotFoundAction must be IGNORE - return; + if ( element != null ) { + loadingState.add( element ); } - loadingState.add( element ); + // else if the element is null, then NotFoundAction must be IGNORE } @Override protected void initializeSubInstancesFromParent(ImmediateCollectionInitializerData data) { - final Initializer initializer = elementAssembler.getInitializer(); + final var initializer = elementAssembler.getInitializer(); if ( initializer != null ) { - final RowProcessingState rowProcessingState = data.getRowProcessingState(); - final PersistentSet set = getCollectionInstance( data ); + final var rowProcessingState = data.getRowProcessingState(); + final var set = getCollectionInstance( data ); assert set != null; for ( Object element : set ) { initializer.initializeInstanceFromParent( element, rowProcessingState ); @@ -93,7 +93,7 @@ protected void initializeSubInstancesFromParent(ImmediateCollectionInitializerDa @Override protected void resolveInstanceSubInitializers(ImmediateCollectionInitializerData data) { - final Initializer initializer = elementAssembler.getInitializer(); + final var initializer = elementAssembler.getInitializer(); if ( initializer != null ) { initializer.resolveKey( data.getRowProcessingState() ); } @@ -111,6 +111,6 @@ public DomainResultAssembler getElementAssembler() { @Override public String toString() { - return "SetInitializer(" + LoggingHelper.toLoggableString( getNavigablePath() ) + ")"; + return "SetInitializer(" + toLoggableString( getNavigablePath() ) + ")"; } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/AggregateEmbeddableInitializerImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/AggregateEmbeddableInitializerImpl.java index 6681381a9304..0ac3e986e1cf 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/AggregateEmbeddableInitializerImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/AggregateEmbeddableInitializerImpl.java @@ -27,7 +27,7 @@ public AggregateEmbeddableInitializerImpl( AssemblerCreationState creationState, boolean isResultInitializer) { super( resultDescriptor, discriminatorFetch, null, parent, creationState, isResultInitializer ); - this.aggregateValuesArrayPositions = resultDescriptor.getAggregateValuesArrayPositions(); + aggregateValuesArrayPositions = resultDescriptor.getAggregateValuesArrayPositions(); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/EmbeddableInitializerImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/EmbeddableInitializerImpl.java index 35fd930e83ee..358a22afe591 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/EmbeddableInitializerImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/EmbeddableInitializerImpl.java @@ -5,11 +5,9 @@ package org.hibernate.sql.results.graph.embeddable.internal; import java.util.Arrays; -import java.util.Collection; import java.util.function.BiConsumer; import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer; -import org.hibernate.engine.internal.ManagedTypeHelper; import org.hibernate.metamodel.mapping.AttributeMapping; import org.hibernate.metamodel.mapping.EmbeddableMappingType; import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart; @@ -21,9 +19,6 @@ import org.hibernate.sql.results.graph.AssemblerCreationState; import org.hibernate.sql.results.graph.DomainResult; import org.hibernate.sql.results.graph.DomainResultAssembler; -import org.hibernate.sql.results.graph.Fetch; -import org.hibernate.sql.results.graph.FetchParent; -import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.Initializer; import org.hibernate.sql.results.graph.InitializerData; import org.hibernate.sql.results.graph.InitializerParent; @@ -38,13 +33,15 @@ import org.checkerframework.checker.nullness.qual.Nullable; +import static org.hibernate.engine.internal.ManagedTypeHelper.isPersistentAttributeInterceptableType; import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer; import static org.hibernate.sql.results.graph.entity.internal.BatchEntityInsideEmbeddableSelectFetchInitializer.BATCH_PROPERTY; /** * @author Steve Ebersole */ -public class EmbeddableInitializerImpl extends AbstractInitializer +public class EmbeddableInitializerImpl + extends AbstractInitializer implements EmbeddableInitializer { private final NavigablePath navigablePath; @@ -70,9 +67,8 @@ public static class EmbeddableInitializerData extends InitializerData implements public EmbeddableInitializerData(EmbeddableInitializerImpl initializer, RowProcessingState rowProcessingState) { super( rowProcessingState ); - this.parentData = initializer.parent == null ? null : initializer.parent.getData( rowProcessingState ); - final int size = initializer.embeddableMappingType.getNumberOfFetchables(); - this.rowState = new Object[ size ]; + parentData = initializer.parent == null ? null : initializer.parent.getData( rowProcessingState ); + rowState = new Object[ initializer.embeddableMappingType.getNumberOfFetchables() ]; } @Override @@ -103,25 +99,24 @@ public EmbeddableInitializerImpl( AssemblerCreationState creationState, boolean isResultInitializer) { super( creationState ); - this.navigablePath = resultDescriptor.getNavigablePath(); - this.embedded = resultDescriptor.getReferencedMappingContainer(); this.parent = (InitializerParent) parent; this.isResultInitializer = isResultInitializer; - this.embeddableMappingType = embedded.getEmbeddableTypeDescriptor(); + navigablePath = resultDescriptor.getNavigablePath(); + embedded = resultDescriptor.getReferencedMappingContainer(); + embeddableMappingType = embedded.getEmbeddableTypeDescriptor(); + isPartOfKey = embedded.isEntityIdentifierMapping() || Initializer.isPartOfKey( navigablePath, parent ); - this.isPartOfKey = embedded.isEntityIdentifierMapping() || Initializer.isPartOfKey( navigablePath, parent ); // We never want to create empty composites for the FK target or PK, otherwise collections would break - final Collection concreteEmbeddableTypes = embeddableMappingType.getConcreteEmbeddableTypes(); - final DomainResultAssembler[][] assemblers = new DomainResultAssembler[concreteEmbeddableTypes.isEmpty() ? 1 : concreteEmbeddableTypes.size()][]; + final var concreteEmbeddableTypes = embeddableMappingType.getConcreteEmbeddableTypes(); + final var assemblers = new DomainResultAssembler[concreteEmbeddableTypes.isEmpty() ? 1 : concreteEmbeddableTypes.size()][]; final @Nullable Initializer[][] subInitializers = new Initializer[assemblers.length][]; final @Nullable Initializer[][] eagerSubInitializers = new Initializer[subInitializers.length][]; final @Nullable Initializer[][] collectionContainingSubInitializers = new Initializer[subInitializers.length][]; + fill( subInitializers ); + fill( eagerSubInitializers ); + fill( collectionContainingSubInitializers ); final int numberOfFetchables = embeddableMappingType.getNumberOfFetchables(); - - Arrays.fill( subInitializers, Initializer.EMPTY_ARRAY ); - Arrays.fill( eagerSubInitializers, Initializer.EMPTY_ARRAY ); - Arrays.fill( collectionContainingSubInitializers, Initializer.EMPTY_ARRAY ); for (int i = 0; i < assemblers.length; i++ ) { assemblers[i] = new DomainResultAssembler[numberOfFetchables]; } @@ -129,18 +124,18 @@ public EmbeddableInitializerImpl( boolean lazyCapable = false; boolean hasLazySubInitializers = false; for ( int stateArrayPosition = 0; stateArrayPosition < numberOfFetchables; stateArrayPosition++ ) { - final Fetchable stateArrayContributor = embeddableMappingType.getFetchable( stateArrayPosition ); - final Fetch fetch = resultDescriptor.findFetch( stateArrayContributor ); - - final DomainResultAssembler stateAssembler = fetch == null - ? new NullValueAssembler<>( stateArrayContributor.getJavaType() ) - : fetch.createAssembler( this, creationState ); + final var stateArrayContributor = embeddableMappingType.getFetchable( stateArrayPosition ); + final var fetch = resultDescriptor.findFetch( stateArrayContributor ); + final var stateAssembler = + fetch == null + ? new NullValueAssembler<>( stateArrayContributor.getJavaType() ) + : fetch.createAssembler( this, creationState ); if ( concreteEmbeddableTypes.isEmpty() ) { assemblers[0][stateArrayPosition] = stateAssembler; } else { - for ( EmbeddableMappingType.ConcreteEmbeddableType concreteEmbeddableType : concreteEmbeddableTypes ) { + for ( var concreteEmbeddableType : concreteEmbeddableTypes ) { if ( concreteEmbeddableType.declaresAttribute( stateArrayPosition ) ) { assemblers[concreteEmbeddableType.getSubclassId()][stateArrayPosition] = stateAssembler; } @@ -148,7 +143,7 @@ public EmbeddableInitializerImpl( } //noinspection unchecked - final Initializer subInitializer = (Initializer) stateAssembler.getInitializer(); + final var subInitializer = (Initializer) stateAssembler.getInitializer(); if ( subInitializer != null ) { for (int subclassId = 0; subclassId < assemblers.length; subclassId++ ) { if ( subInitializers[subclassId] == Initializer.EMPTY_ARRAY ) { @@ -164,8 +159,8 @@ public EmbeddableInitializerImpl( hasLazySubInitializers = hasLazySubInitializers || subInitializer.hasLazySubInitializers(); assert fetch != null; - final FetchParent fetchParent; - if ( ( fetchParent = fetch.asFetchParent() ) != null && fetchParent.containsCollectionFetches() + final var fetchParent = fetch.asFetchParent(); + if ( fetchParent != null && fetchParent.containsCollectionFetches() || subInitializer.isCollectionInitializer() ) { if ( collectionContainingSubInitializers[subclassId] == Initializer.EMPTY_ARRAY ) { collectionContainingSubInitializers[subclassId] = new Initializer[numberOfFetchables]; @@ -181,22 +176,29 @@ public EmbeddableInitializerImpl( } } this.assemblers = assemblers; - this.discriminatorAssembler = discriminatorFetch != null - ? (BasicResultAssembler) discriminatorFetch.createAssembler( this, creationState ) - : null; + this.discriminatorAssembler = + discriminatorFetch == null + ? null + : (BasicResultAssembler) + discriminatorFetch.createAssembler( this, creationState ); this.nullIndicatorAssembler = nullIndicatorResult == null ? null : nullIndicatorResult.createResultAssembler( this, creationState ); this.subInitializers = subInitializers; - this.subInitializersForResolveFromInitialized = isEnhancedForLazyLoading( embeddableMappingType ) - ? subInitializers - : eagerSubInitializers; + this.subInitializersForResolveFromInitialized = + isEnhancedForLazyLoading( embeddableMappingType ) + ? subInitializers + : eagerSubInitializers; this.collectionContainingSubInitializers = collectionContainingSubInitializers; this.lazyCapable = lazyCapable; this.hasLazySubInitializer = hasLazySubInitializers; } + private static void fill(@Nullable Initializer[][] initializers) { + Arrays.fill( initializers, Initializer.EMPTY_ARRAY ); + } + private static boolean isEnhancedForLazyLoading(EmbeddableMappingType embeddableMappingType) { - return ManagedTypeHelper.isPersistentAttributeInterceptableType( + return isPersistentAttributeInterceptableType( embeddableMappingType.getRepresentationStrategy().getMappedJavaType().getJavaTypeClass() ); } @@ -249,55 +251,58 @@ protected InitializerData createInitializerData(RowProcessingState rowProcessing @Override public void resolveKey(EmbeddableInitializerData data) { - if ( data.getState() != State.UNINITIALIZED ) { - return; - } - data.setInstance( null ); - if ( discriminatorAssembler != null ) { - assert embeddableMappingType.getDiscriminatorMapping() != null; - // todo: add more info into EmbeddableDiscriminatorConverter to extract this details object directly - final Object discriminatorValue = discriminatorAssembler.extractRawValue( data.getRowProcessingState() ); - data.concreteEmbeddableType = discriminatorValue == null - ? null - : embeddableMappingType.findSubtypeByDiscriminator( discriminatorValue ); - } - if ( isPartOfKey ) { - data.setState( State.KEY_RESOLVED ); - if ( subInitializers[data.getSubclassId()].length == 0 ) { - // Resolve the component early to know if the key is missing or not - resolveInstance( data ); + if ( data.getState() == State.UNINITIALIZED ) { + data.setInstance( null ); + if ( discriminatorAssembler != null ) { + assert embeddableMappingType.getDiscriminatorMapping() != null; + // todo: add more info into EmbeddableDiscriminatorConverter to extract this details object directly + final Object discriminatorValue = + discriminatorAssembler.extractRawValue( data.getRowProcessingState() ); + data.concreteEmbeddableType = + discriminatorValue == null + ? null + : embeddableMappingType.findSubtypeByDiscriminator( discriminatorValue ); + } + if ( isPartOfKey ) { + data.setState( State.KEY_RESOLVED ); + if ( subInitializers[data.getSubclassId()].length == 0 ) { + // Resolve the component early to know if the key is missing or not + resolveInstance( data ); + } + else { + resolveKeySubInitializers( data ); + } } else { - resolveKeySubInitializers( data ); + super.resolveKey( data ); } } - else { - super.resolveKey( data ); - } } @Override public void resetResolvedEntityRegistrations(RowProcessingState rowProcessingState) { - final EmbeddableInitializerData data = getData( rowProcessingState ); - for ( Initializer initializer : subInitializers[data.getSubclassId()] ) { + final var data = getData( rowProcessingState ); + for ( var initializer : subInitializers[data.getSubclassId()] ) { if ( initializer != null ) { - final EntityInitializer entityInitializer = initializer.asEntityInitializer(); - final EmbeddableInitializer embeddableInitializer; + final var entityInitializer = initializer.asEntityInitializer(); if ( entityInitializer != null ) { entityInitializer.resetResolvedEntityRegistrations( rowProcessingState ); } - else if ( ( embeddableInitializer = initializer.asEmbeddableInitializer() ) != null ) { - embeddableInitializer.resetResolvedEntityRegistrations( rowProcessingState ); + else { + final var embeddableInitializer = initializer.asEmbeddableInitializer(); + if ( embeddableInitializer != null ) { + embeddableInitializer.resetResolvedEntityRegistrations( rowProcessingState ); + } } } } } private void resolveKeySubInitializers(EmbeddableInitializerData data) { - final RowProcessingState rowProcessingState = data.getRowProcessingState(); - for ( Initializer initializer : subInitializers[data.getSubclassId()] ) { + final var rowProcessingState = data.getRowProcessingState(); + for ( var initializer : subInitializers[data.getSubclassId()] ) { if ( initializer != null ) { - final InitializerData subData = initializer.getData( rowProcessingState ); + final var subData = initializer.getData( rowProcessingState ); initializer.resolveKey( subData ); if ( subData.getState() == State.MISSING ) { data.setState( State.MISSING ); @@ -314,9 +319,9 @@ public void resolveFromPreviousRow(EmbeddableInitializerData data) { data.setState( State.MISSING ); } else { - final RowProcessingState rowProcessingState = data.getRowProcessingState(); + final var rowProcessingState = data.getRowProcessingState(); // When a previous row initialized this entity already, we only need to process collections - for ( Initializer initializer : collectionContainingSubInitializers[data.getSubclassId()] ) { + for ( var initializer : collectionContainingSubInitializers[data.getSubclassId()] ) { if ( initializer != null ) { initializer.resolveFromPreviousRow( rowProcessingState ); } @@ -328,13 +333,11 @@ public void resolveFromPreviousRow(EmbeddableInitializerData data) { @Override public void resolveInstance(EmbeddableInitializerData data) { - if ( data.getState() != State.KEY_RESOLVED ) { - return; + if ( data.getState() == State.KEY_RESOLVED ) { + data.setState( State.RESOLVED ); + extractRowState( data ); + prepareCompositeInstance( data ); } - - data.setState( State.RESOLVED ); - extractRowState( data ); - prepareCompositeInstance( data ); } @Override @@ -347,10 +350,10 @@ public void resolveInstance(@Nullable Object instance, EmbeddableInitializerData data.setState( State.INITIALIZED ); data.setInstance( instance ); final int subclassId = data.getSubclassId(); - final RowProcessingState rowProcessingState = data.getRowProcessingState(); + final var rowProcessingState = data.getRowProcessingState(); resolveInstanceSubInitializers( subclassId, instance, rowProcessingState ); if ( rowProcessingState.needsResolveState() ) { - for ( DomainResultAssembler assembler : assemblers[subclassId] ) { + for ( var assembler : assemblers[subclassId] ) { assembler.resolveState( rowProcessingState ); } } @@ -376,37 +379,37 @@ private void resolveInstanceSubInitializers(int subclassId, Object instance, Row @Override public void initializeInstance(EmbeddableInitializerData data) { - if ( data.getState() != State.RESOLVED ) { - return; - } - data.setState( State.INITIALIZED ); + if ( data.getState() == State.RESOLVED ) { + data.setState( State.INITIALIZED ); - if ( embedded.getParentInjectionAttributePropertyAccess() != null || embedded instanceof VirtualModelPart ) { - handleParentInjection( data ); + if ( embedded.getParentInjectionAttributePropertyAccess() != null + || embedded instanceof VirtualModelPart ) { + handleParentInjection( data ); - final var lazyInitializer = extractLazyInitializer( data.getInstance() ); - // If the composite instance has a lazy initializer attached, this means that the embeddable is actually virtual - // and the compositeInstance == entity, so we have to inject the row state into the entity when it finishes resolution - if ( lazyInitializer != null ) { - if ( parent != null ) { - embeddableMappingType.setValues( lazyInitializer.getImplementation(), data.rowState ); + final var lazyInitializer = extractLazyInitializer( data.getInstance() ); + // If the composite instance has a lazy initializer attached, this means that the embeddable is actually virtual + // and the compositeInstance == entity, so we have to inject the row state into the entity when it finishes resolution + if ( lazyInitializer != null ) { + if ( parent != null ) { + embeddableMappingType.setValues( lazyInitializer.getImplementation(), data.rowState ); + } + else { + // At this point, createEmptyCompositesEnabled is always true, so we generate + // the composite instance. + // + // NOTE: `valuesAccess` is set to null to indicate that all values are null, + // as opposed to returning the all-null value array. the instantiator + // interprets that as the values are not known or were all null. + final Object target = + embeddableMappingType.getRepresentationStrategy().getInstantiator() + .instantiate( data ); + lazyInitializer.setImplementation( target ); + } } else { - // At this point, createEmptyCompositesEnabled is always true, so we generate - // the composite instance. - // - // NOTE: `valuesAccess` is set to null to indicate that all values are null, - // as opposed to returning the all-null value array. the instantiator - // interprets that as the values are not known or were all null. - final Object target = - embeddableMappingType.getRepresentationStrategy().getInstantiator() - .instantiate( data ); - lazyInitializer.setImplementation( target ); + embeddableMappingType.setValues( data.getInstance(), data.rowState ); } } - else { - embeddableMappingType.setValues( data.getInstance(), data.rowState ); - } } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/NonAggregatedIdentifierMappingInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/NonAggregatedIdentifierMappingInitializer.java index 70c57c653ca6..766ea04b8168 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/NonAggregatedIdentifierMappingInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/NonAggregatedIdentifierMappingInitializer.java @@ -20,8 +20,6 @@ import org.hibernate.sql.results.graph.AssemblerCreationState; import org.hibernate.sql.results.graph.DomainResultAssembler; import org.hibernate.sql.results.graph.Fetch; -import org.hibernate.sql.results.graph.FetchParent; -import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.Initializer; import org.hibernate.sql.results.graph.InitializerData; import org.hibernate.sql.results.graph.InitializerParent; @@ -68,15 +66,21 @@ public NonAggregatedIdentifierMappingInitializerData( NonAggregatedIdentifierMappingInitializer initializer, RowProcessingState rowProcessingState) { super( rowProcessingState ); - isFindByIdLookup = - !initializer.hasIdClass && rowProcessingState.getEntityId() != null - && initializer.navigablePath.getParent().getParent() == null - && initializer.navigablePath instanceof EntityIdentifierNavigablePath; + isFindByIdLookup = isIsFindByIdLookup( initializer, rowProcessingState ); parentData = initializer.parent == null ? null : initializer.parent.getData( rowProcessingState ); final var virtualIdEmbeddable = initializer.embedded.getEmbeddableTypeDescriptor(); final int size = virtualIdEmbeddable.getNumberOfFetchables(); - virtualIdState = new Object[ size ]; - idClassState = new Object[ size ]; + virtualIdState = new Object[size]; + idClassState = new Object[size]; + } + + private boolean isIsFindByIdLookup( + NonAggregatedIdentifierMappingInitializer initializer, + RowProcessingState rowProcessingState) { + return !initializer.hasIdClass + && rowProcessingState.getEntityId() != null + && initializer.navigablePath.getParent().getParent() == null + && initializer.navigablePath instanceof EntityIdentifierNavigablePath; } @Override @@ -112,23 +116,24 @@ protected NonAggregatedIdentifierMappingInitializer( boolean isResultInitializer, Function fetchConverter) { super( creationState ); - this.navigablePath = resultDescriptor.getNavigablePath(); - this.embedded = - (NonAggregatedIdentifierMapping) - resultDescriptor.getReferencedMappingContainer(); this.parent = parent; this.isResultInitializer = isResultInitializer; - this.virtualIdEmbeddable = embedded.getEmbeddableTypeDescriptor(); - this.representationEmbeddable = embedded.getMappedIdEmbeddableTypeDescriptor(); - this.embeddableInstantiator = representationEmbeddable.getRepresentationStrategy().getInstantiator(); - this.hasIdClass = embedded.hasContainingClass() && virtualIdEmbeddable != representationEmbeddable; + navigablePath = resultDescriptor.getNavigablePath(); + embedded = + (NonAggregatedIdentifierMapping) + resultDescriptor.getReferencedMappingContainer(); + + virtualIdEmbeddable = embedded.getEmbeddableTypeDescriptor(); + representationEmbeddable = embedded.getMappedIdEmbeddableTypeDescriptor(); + embeddableInstantiator = representationEmbeddable.getRepresentationStrategy().getInstantiator(); + hasIdClass = embedded.hasContainingClass() && virtualIdEmbeddable != representationEmbeddable; final int size = virtualIdEmbeddable.getNumberOfFetchables(); final var assemblers = new DomainResultAssembler[size]; this.assemblers = assemblers; final Initializer[] initializers = new Initializer[assemblers.length]; - final Initializer[] eagerSubInitializers = new Initializer[assemblers.length]; +// final Initializer[] eagerSubInitializers = new Initializer[assemblers.length]; final Initializer[] collectionContainingSubInitializers = new Initializer[assemblers.length]; boolean empty = true; boolean emptyEager = true; @@ -136,24 +141,25 @@ protected NonAggregatedIdentifierMappingInitializer( boolean lazyCapable = false; boolean hasLazySubInitializers = false; for ( int i = 0; i < size; i++ ) { - final Fetchable stateArrayContributor = virtualIdEmbeddable.getFetchable( i ); - final Fetch fetch = fetchConverter.apply( resultDescriptor.findFetch( stateArrayContributor ) ); + final var stateArrayContributor = virtualIdEmbeddable.getFetchable( i ); + final var fetch = fetchConverter.apply( resultDescriptor.findFetch( stateArrayContributor ) ); - final var stateAssembler = fetch == null - ? new NullValueAssembler<>( stateArrayContributor.getJavaType() ) - : fetch.createAssembler( this, creationState ); + final var stateAssembler = + fetch == null + ? new NullValueAssembler<>( stateArrayContributor.getJavaType() ) + : fetch.createAssembler( this, creationState ); assemblers[i] = stateAssembler; final var initializer = stateAssembler.getInitializer(); if ( initializer != null ) { if ( initializer.isEager() ) { - eagerSubInitializers[i] = initializer; +// eagerSubInitializers[i] = initializer; hasLazySubInitializers = hasLazySubInitializers || initializer.hasLazySubInitializers(); emptyEager = false; assert fetch != null; - final FetchParent fetchParent; - if ( ( fetchParent = fetch.asFetchParent() ) != null && fetchParent.containsCollectionFetches() + final var fetchParent = fetch.asFetchParent(); + if ( fetchParent != null && fetchParent.containsCollectionFetches() || initializer.isCollectionInitializer() ) { collectionContainingSubInitializers[i] = initializer; emptyCollectionInitializers = false; @@ -303,7 +309,7 @@ public void resolveInstance(@Nullable Object instance, NonAggregatedIdentifierMa final var rowProcessingState = data.getRowProcessingState(); resolveInstanceSubInitializers( instance, rowProcessingState ); if ( rowProcessingState.needsResolveState() ) { - for ( DomainResultAssembler assembler : assemblers ) { + for ( var assembler : assemblers ) { assembler.resolveState( rowProcessingState ); } } @@ -351,7 +357,7 @@ public void initializeInstance(NonAggregatedIdentifierMappingInitializerData dat @Override protected void forEachSubInitializer(BiConsumer, RowProcessingState> consumer, InitializerData data) { final var rowProcessingState = data.getRowProcessingState(); - for ( Initializer initializer : initializers ) { + for ( var initializer : initializers ) { if ( initializer != null ) { consumer.accept( initializer, rowProcessingState ); } @@ -378,7 +384,7 @@ private void extractRowState(NonAggregatedIdentifierMappingInitializerData data) final var virtualIdAttribute = virtualIdEmbeddable.getAttributeMapping( i ); final var mappedIdAttribute = representationEmbeddable.getAttributeMapping( i ); if ( virtualIdAttribute instanceof ToOneAttributeMapping toOneAttributeMapping - && !( mappedIdAttribute instanceof ToOneAttributeMapping ) ) { + && !( mappedIdAttribute instanceof ToOneAttributeMapping ) ) { final Object associationKey = toOneAttributeMapping.getForeignKeyDescriptor() .getAssociationKeyFromSide( @@ -433,6 +439,7 @@ public boolean hasLazySubInitializers() { @Override public String toString() { - return "NonAggregatedIdentifierMappingInitializer(" + navigablePath + ") : `" + getInitializedPart().getJavaType().getJavaTypeClass() + "`"; + return "NonAggregatedIdentifierMappingInitializer(" + navigablePath + ") : `" + + getInitializedPart().getJavaType().getJavaTypeClass() + "`"; } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/AbstractBatchEntitySelectFetchInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/AbstractBatchEntitySelectFetchInitializer.java index 4f3db569faf4..48260ae4e09d 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/AbstractBatchEntitySelectFetchInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/AbstractBatchEntitySelectFetchInitializer.java @@ -4,21 +4,14 @@ */ package org.hibernate.sql.results.graph.entity.internal; -import org.hibernate.EntityFilterException; -import org.hibernate.FetchNotFoundException; import org.hibernate.Hibernate; -import org.hibernate.annotations.NotFoundAction; import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor; -import org.hibernate.engine.spi.EntityHolder; import org.hibernate.engine.spi.EntityKey; -import org.hibernate.engine.spi.PersistenceContext; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.metamodel.mapping.AttributeMapping; import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping; import org.hibernate.persister.entity.EntityPersister; -import org.hibernate.proxy.HibernateProxy; -import org.hibernate.proxy.LazyInitializer; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.results.graph.AssemblerCreationState; import org.hibernate.sql.results.graph.DomainResult; @@ -49,9 +42,15 @@ public AbstractBatchEntitySelectFetchInitializerData( AbstractBatchEntitySelectFetchInitializer initializer, RowProcessingState rowProcessingState) { super( initializer, rowProcessingState ); + batchDisabled = isBatchDisabled( initializer, rowProcessingState ); + } - batchDisabled = rowProcessingState.isScrollResult() - || !rowProcessingState.getLoadQueryInfluencers().effectivelyBatchLoadable( initializer.toOneMapping.getEntityMappingType().getEntityPersister() ); + private static boolean isBatchDisabled( + AbstractBatchEntitySelectFetchInitializer initializer, + RowProcessingState rowProcessingState) { + return rowProcessingState.isScrollResult() + || !rowProcessingState.getLoadQueryInfluencers() + .effectivelyBatchLoadable( initializer.toOneMapping.getEntityMappingType().getEntityPersister() ); } } @@ -65,7 +64,9 @@ public AbstractBatchEntitySelectFetchInitializer( AssemblerCreationState creationState) { super( parent, toOneMapping, fetchedNavigable, concreteDescriptor, keyResult, affectedByFilter, creationState ); //noinspection unchecked - this.owningEntityInitializer = (EntityInitializer) Initializer.findOwningEntityInitializer( parent ); + owningEntityInitializer = + (EntityInitializer) + Initializer.findOwningEntityInitializer( parent ); assert owningEntityInitializer != null : "This initializer requires an owning parent entity initializer"; } @@ -73,46 +74,42 @@ public AbstractBatchEntitySelectFetchInitializer( @Override public void resolveKey(Data data) { - if ( data.getState() != State.UNINITIALIZED ) { - return; - } - - data.entityKey = null; - data.setInstance( null ); - final RowProcessingState rowProcessingState = data.getRowProcessingState(); - //noinspection unchecked - final Initializer initializer = (Initializer) keyAssembler.getInitializer(); - if ( initializer != null ) { - final InitializerData subData = initializer.getData( rowProcessingState ); - initializer.resolveKey( subData ); - data.entityIdentifier = null; - data.setState( subData.getState() == State.MISSING ? State.MISSING : State.KEY_RESOLVED ); - } - else { - data.entityIdentifier = keyAssembler.assemble( rowProcessingState ); - data.setState( data.entityIdentifier == null ? State.MISSING : State.KEY_RESOLVED ); + if ( data.getState() == State.UNINITIALIZED ) { + data.entityKey = null; + data.setInstance( null ); + final var rowProcessingState = data.getRowProcessingState(); + //noinspection unchecked + final var initializer = (Initializer) keyAssembler.getInitializer(); + if ( initializer != null ) { + final var subData = initializer.getData( rowProcessingState ); + initializer.resolveKey( subData ); + data.entityIdentifier = null; + data.setState( subData.getState() == State.MISSING ? State.MISSING : State.KEY_RESOLVED ); + } + else { + data.entityIdentifier = keyAssembler.assemble( rowProcessingState ); + data.setState( data.entityIdentifier == null ? State.MISSING : State.KEY_RESOLVED ); + } } } @Override public void resolveInstance(Data data) { - if ( data.getState() != State.KEY_RESOLVED ) { - return; - } - - data.setState( State.RESOLVED ); - final RowProcessingState rowProcessingState = data.getRowProcessingState(); - if ( data.entityIdentifier == null ) { - // entityIdentifier can be null if the identifier is based on an initializer - data.entityIdentifier = keyAssembler.assemble( rowProcessingState ); + if ( data.getState() == State.KEY_RESOLVED ) { + data.setState( State.RESOLVED ); + final var rowProcessingState = data.getRowProcessingState(); if ( data.entityIdentifier == null ) { - data.entityKey = null; - data.setInstance( null ); - data.setState( State.MISSING ); - return; + // entityIdentifier can be null if the identifier is based on an initializer + data.entityIdentifier = keyAssembler.assemble( rowProcessingState ); + if ( data.entityIdentifier == null ) { + data.entityKey = null; + data.setInstance( null ); + data.setState( State.MISSING ); + return; + } } + resolveInstanceFromIdentifier( data ); } - resolveInstanceFromIdentifier( data ); } protected void resolveInstanceFromIdentifier(Data data) { @@ -136,11 +133,16 @@ public void resolveInstance(Object instance, Data data) { data.setState( State.MISSING ); data.entityKey = null; data.setInstance( null ); - return; } - final RowProcessingState rowProcessingState = data.getRowProcessingState(); + else { + resolve( instance, data ); + } + } + + private void resolve(Object instance, Data data) { + final var rowProcessingState = data.getRowProcessingState(); // Only need to extract the identifier if the identifier has a many to one - final LazyInitializer lazyInitializer = extractLazyInitializer( instance ); + final var lazyInitializer = extractLazyInitializer( instance ); data.entityKey = null; data.entityIdentifier = null; if ( lazyInitializer == null ) { @@ -157,15 +159,19 @@ && getAttributeInterceptor( instance ) data.setState( State.RESOLVED ); data.entityIdentifier = enhancementInterceptor.getIdentifier(); } + if ( keyIsEager && data.entityIdentifier == null ) { + data.entityIdentifier = + concreteDescriptor.getIdentifier( instance, + rowProcessingState.getSession() ); + } } else { - // If the entity initializer is null, we know the entity is fully initialized, - // otherwise it will be initialized by some other initializer + // If the entity initializer is null, we know the entity is fully initialized; + // otherwise, it will be initialized by some other initializer data.setState( State.RESOLVED ); - data.entityIdentifier = concreteDescriptor.getIdentifier( instance, rowProcessingState.getSession() ); - } - if ( keyIsEager && data.entityIdentifier == null ) { - data.entityIdentifier = concreteDescriptor.getIdentifier( instance, rowProcessingState.getSession() ); + data.entityIdentifier = + concreteDescriptor.getIdentifier( instance, + rowProcessingState.getSession() ); } } else if ( lazyInitializer.isUninitialized() ) { @@ -185,7 +191,7 @@ else if ( lazyInitializer.isUninitialized() ) { resolveInstanceFromIdentifier( data ); } if ( keyIsEager ) { - final Initializer initializer = keyAssembler.getInitializer(); + final var initializer = keyAssembler.getInitializer(); assert initializer != null; initializer.resolveInstance( data.entityIdentifier, rowProcessingState ); } @@ -197,21 +203,23 @@ else if ( rowProcessingState.needsResolveState() ) { @Override public void initializeInstance(Data data) { - if ( data.getState() != State.RESOLVED ) { - return; - } - data.setState( State.INITIALIZED ); - if ( data.batchDisabled ) { - Hibernate.initialize( data.getInstance() ); + if ( data.getState() == State.RESOLVED ) { + data.setState( State.INITIALIZED ); + if ( data.batchDisabled ) { + Hibernate.initialize( data.getInstance() ); + } } } protected Object getExistingInitializedInstance(Data data) { - final SharedSessionContractImplementor session = data.getRowProcessingState().getSession(); - final PersistenceContext persistenceContext = session.getPersistenceContextInternal(); - final EntityHolder holder = persistenceContext.getEntityHolder( data.entityKey ); - if ( holder != null && holder.getEntity() != null && holder.isEventuallyInitialized() ) { - return holder.getEntity(); + final var session = data.getRowProcessingState().getSession(); + final var persistenceContext = session.getPersistenceContextInternal(); + final var holder = persistenceContext.getEntityHolder( data.entityKey ); + if ( holder != null ) { + final Object entity = holder.getEntity(); + if ( entity != null && holder.isEventuallyInitialized() ) { + return entity; + } } // we need to register a resolution listener only if there is not an already initialized instance // or an instance that another initializer is loading @@ -227,10 +235,11 @@ protected void registerToBatchFetchQueue(Data data) { @Override public void initializeInstanceFromParent(Object parentInstance, Data data) { - final AttributeMapping attributeMapping = getInitializedPart().asAttributeMapping(); - final Object instance = attributeMapping != null - ? attributeMapping.getValue( parentInstance ) - : parentInstance; + final var attributeMapping = getInitializedPart().asAttributeMapping(); + final Object instance = + attributeMapping != null + ? attributeMapping.getValue( parentInstance ) + : parentInstance; // No need to initialize these fields data.entityKey = null; data.setInstance( null ); @@ -238,7 +247,7 @@ public void initializeInstanceFromParent(Object parentInstance, Data data) { data.setState( State.MISSING ); } else { - final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( instance ); + final var lazyInitializer = extractLazyInitializer( instance ); if ( lazyInitializer != null && lazyInitializer.isUninitialized() ) { data.entityKey = new EntityKey( lazyInitializer.getInternalIdentifier(), concreteDescriptor ); registerToBatchFetchQueue( data ); @@ -252,47 +261,28 @@ protected static Object loadInstance( ToOneAttributeMapping toOneMapping, boolean affectedByFilter, SharedSessionContractImplementor session) { - final Object instance = session.internalLoad( - entityKey.getEntityName(), - entityKey.getIdentifier(), - true, - toOneMapping.isInternalLoadNullable() - ); + final String entityName = entityKey.getEntityName(); + final Object identifier = entityKey.getIdentifier(); + final Object instance = + session.internalLoad( entityName, identifier, true, + toOneMapping.isInternalLoadNullable() ); if ( instance == null ) { - if ( toOneMapping.getNotFoundAction() != NotFoundAction.IGNORE ) { - if ( affectedByFilter ) { - throw new EntityFilterException( - entityKey.getEntityName(), - entityKey.getIdentifier(), - toOneMapping.getNavigableRole().getFullPath() - ); - } - if ( toOneMapping.getNotFoundAction() == NotFoundAction.EXCEPTION ) { - throw new FetchNotFoundException( entityKey.getEntityName(), entityKey.getIdentifier() ); - } - } + checkNotFound( toOneMapping, affectedByFilter, entityName, identifier ); } return instance; } protected AttributeMapping[] getParentEntityAttributes(String attributeName) { - final EntityPersister entityDescriptor = owningEntityInitializer.getEntityDescriptor(); - final AttributeMapping[] parentEntityAttributes = new AttributeMapping[ + final var entityDescriptor = owningEntityInitializer.getEntityDescriptor(); + final int size = entityDescriptor.getRootEntityDescriptor() - .getSubclassEntityNames() - .size() - ]; - parentEntityAttributes[entityDescriptor.getSubclassId()] = getParentEntityAttribute( - entityDescriptor, - toOneMapping, - attributeName - ); + .getSubclassEntityNames().size(); + final var parentEntityAttributes = new AttributeMapping[size]; + parentEntityAttributes[ entityDescriptor.getSubclassId() ] = + getParentEntityAttribute( entityDescriptor, toOneMapping, attributeName ); for ( EntityMappingType subMappingType : entityDescriptor.getSubMappingTypes() ) { - parentEntityAttributes[subMappingType.getSubclassId()] = getParentEntityAttribute( - subMappingType, - toOneMapping, - attributeName - ); + parentEntityAttributes[ subMappingType.getSubclassId() ] = + getParentEntityAttribute( subMappingType, toOneMapping, attributeName ); } return parentEntityAttributes; } @@ -301,14 +291,14 @@ protected static AttributeMapping getParentEntityAttribute( EntityMappingType subMappingType, ToOneAttributeMapping referencedModelPart, String attributeName) { - final AttributeMapping parentAttribute = subMappingType.findAttributeMapping( attributeName ); - if ( parentAttribute != null && parentAttribute.getDeclaringType() == referencedModelPart.getDeclaringType() - .findContainingEntityMapping() ) { - // These checks are needed to avoid setting the instance using the wrong (child's) model part or - // setting it multiple times in case parent and child share the same attribute name for the association. - return parentAttribute; - } - return null; + final var parentAttribute = subMappingType.findAttributeMapping( attributeName ); + // These checks are needed to avoid setting the instance using the wrong (child's) model part or + // setting it multiple times in case parent and child share the same attribute name for the association. + return parentAttribute != null + && parentAttribute.getDeclaringType() + == referencedModelPart.getDeclaringType().findContainingEntityMapping() + ? parentAttribute + : null; } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/BatchEntityInsideEmbeddableSelectFetchInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/BatchEntityInsideEmbeddableSelectFetchInitializer.java index 773651c50370..3752e3ce4b35 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/BatchEntityInsideEmbeddableSelectFetchInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/BatchEntityInsideEmbeddableSelectFetchInitializer.java @@ -4,20 +4,14 @@ */ package org.hibernate.sql.results.graph.entity.internal; +import java.io.Serial; import java.io.Serializable; import java.util.ArrayList; import java.util.HashMap; import java.util.List; -import java.util.Map; -import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.EntityKey; -import org.hibernate.engine.spi.PersistenceContext; -import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.internal.log.LoggingHelper; import org.hibernate.metamodel.mapping.AttributeMapping; -import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.property.access.spi.Getter; @@ -31,6 +25,8 @@ import org.hibernate.sql.results.jdbc.spi.RowProcessingState; import org.hibernate.type.Type; +import static org.hibernate.internal.log.LoggingHelper.toLoggableString; + public class BatchEntityInsideEmbeddableSelectFetchInitializer extends AbstractBatchEntitySelectFetchInitializer { protected final Setter referencedModelPartSetter; protected final AttributeMapping[] rootEmbeddableAttributes; @@ -46,7 +42,7 @@ public class BatchEntityInsideEmbeddableSelectFetchInitializer extends AbstractB public String toString() { return ""; } - + @Serial public Object readResolve() { return BATCH_PROPERTY; } @@ -72,21 +68,18 @@ public BatchEntityInsideEmbeddableSelectFetchInitializer( AssemblerCreationState creationState) { super( parentAccess, referencedModelPart, fetchedNavigable, concreteDescriptor, keyResult, affectedByFilter, creationState ); - this.referencedModelPartSetter = referencedModelPart.getAttributeMetadata().getPropertyAccess().getSetter(); - final String rootEmbeddablePropertyName = getRootEmbeddablePropertyName( - owningEntityInitializer, - parentAccess, - referencedModelPart - ); - this.rootEmbeddableAttributes = getParentEntityAttributes( rootEmbeddablePropertyName ); - final Getter[] getters = new Getter[rootEmbeddableAttributes.length]; + referencedModelPartSetter = referencedModelPart.getAttributeMetadata().getPropertyAccess().getSetter(); + final String rootEmbeddablePropertyName = + getRootEmbeddablePropertyName( owningEntityInitializer, parentAccess, referencedModelPart ); + rootEmbeddableAttributes = getParentEntityAttributes( rootEmbeddablePropertyName ); + final var getters = new Getter[rootEmbeddableAttributes.length]; for ( int i = 0; i < rootEmbeddableAttributes.length; i++ ) { if ( rootEmbeddableAttributes[i] != null ) { getters[i] = rootEmbeddableAttributes[i].getAttributeMetadata().getPropertyAccess().getGetter(); } } - this.rootEmbeddableGetters = getters; - this.rootEmbeddablePropertyTypes = getParentEntityAttributeTypes( rootEmbeddablePropertyName ); + rootEmbeddableGetters = getters; + rootEmbeddablePropertyTypes = getParentEntityAttributeTypes( rootEmbeddablePropertyName ); } @Override @@ -95,22 +88,22 @@ protected InitializerData createInitializerData(RowProcessingState rowProcessing } protected Type[] getParentEntityAttributeTypes(String attributeName) { - final EntityPersister entityDescriptor = owningEntityInitializer.getEntityDescriptor(); - final Type[] attributeTypes = new Type[ + final var entityDescriptor = owningEntityInitializer.getEntityDescriptor(); + final int size = entityDescriptor.getRootEntityDescriptor() - .getSubclassEntityNames() - .size() - ]; + .getSubclassEntityNames().size(); + final var attributeTypes = new Type[size]; initializeAttributeType( attributeTypes, entityDescriptor, attributeName ); - for ( EntityMappingType subMappingType : entityDescriptor.getSubMappingTypes() ) { + for ( var subMappingType : entityDescriptor.getSubMappingTypes() ) { initializeAttributeType( attributeTypes, subMappingType.getEntityPersister(), attributeName ); } return attributeTypes; } protected void initializeAttributeType(Type[] attributeTypes, EntityPersister entityDescriptor, String attributeName) { - if ( rootEmbeddableAttributes[entityDescriptor.getSubclassId()] != null ) { - attributeTypes[entityDescriptor.getSubclassId()] = entityDescriptor.getPropertyType( attributeName ); + final int subclassId = entityDescriptor.getSubclassId(); + if ( rootEmbeddableAttributes[subclassId] != null ) { + attributeTypes[subclassId] = entityDescriptor.getPropertyType( attributeName ); } } @@ -125,23 +118,24 @@ public void initializeInstance(BatchEntityInsideEmbeddableSelectFetchInitializer super.initializeInstance( data ); // todo: check why this can't be moved to #registerToBatchFetchQueue if ( data.getInstance() == BATCH_PROPERTY ) { - final RowProcessingState rowProcessingState = data.getRowProcessingState(); - final InitializerData owningData = owningEntityInitializer.getData( rowProcessingState ); - final int owningEntitySubclassId = owningEntityInitializer.getConcreteDescriptor( owningData ).getSubclassId(); - final AttributeMapping rootEmbeddableAttribute = rootEmbeddableAttributes[owningEntitySubclassId]; + final var rowProcessingState = data.getRowProcessingState(); + final var owningData = owningEntityInitializer.getData( rowProcessingState ); + final int owningEntitySubclassId = + owningEntityInitializer.getConcreteDescriptor( owningData ) + .getSubclassId(); + final var rootEmbeddableAttribute = rootEmbeddableAttributes[owningEntitySubclassId]; if ( rootEmbeddableAttribute != null ) { - HashMap> toBatchLoad = data.toBatchLoad; + var toBatchLoad = data.toBatchLoad; if ( toBatchLoad == null ) { toBatchLoad = data.toBatchLoad = new HashMap<>(); } - toBatchLoad.computeIfAbsent( data.entityKey, key -> new ArrayList<>() ).add( - new ParentInfo( + toBatchLoad.computeIfAbsent( data.entityKey, key -> new ArrayList<>() ) + .add( new ParentInfo( owningEntityInitializer.getTargetInstance( owningData ), parent.getResolvedInstance( rowProcessingState ), rootEmbeddableAttribute.getStateArrayPosition(), owningEntitySubclassId - ) - ); + ) ); } } } @@ -171,20 +165,20 @@ public ParentInfo( @Override public void endLoading(BatchEntityInsideEmbeddableSelectFetchInitializerData data) { super.endLoading( data ); - final HashMap> toBatchLoad = data.toBatchLoad; + final var toBatchLoad = data.toBatchLoad; if ( toBatchLoad != null ) { - for ( Map.Entry> entry : toBatchLoad.entrySet() ) { - final EntityKey entityKey = entry.getKey(); - final List parentInfos = entry.getValue(); - final SharedSessionContractImplementor session = data.getRowProcessingState().getSession(); - final SessionFactoryImplementor factory = session.getFactory(); - final PersistenceContext persistenceContext = session.getPersistenceContextInternal(); + for ( var entry : toBatchLoad.entrySet() ) { + final var entityKey = entry.getKey(); + final var parentInfos = entry.getValue(); + final var session = data.getRowProcessingState().getSession(); + final var factory = session.getFactory(); + final var persistenceContext = session.getPersistenceContextInternal(); final Object loadedInstance = loadInstance( entityKey, toOneMapping, affectedByFilter, session ); for ( ParentInfo parentInfo : parentInfos ) { final Object parentEntityInstance = parentInfo.parentEntityInstance; - final EntityEntry parentEntityEntry = persistenceContext.getEntry( parentEntityInstance ); + final var parentEntityEntry = persistenceContext.getEntry( parentEntityInstance ); referencedModelPartSetter.set( parentInfo.parentInstance, loadedInstance ); - final Object[] loadedState = parentEntityEntry.getLoadedState(); + final var loadedState = parentEntityEntry.getLoadedState(); if ( loadedState != null ) { /* E.g. @@ -194,11 +188,12 @@ public void endLoading(BatchEntityInsideEmbeddableSelectFetchInitializerData dat The value of RootEmbeddable is needed to update the ParentEntity loaded state */ final int parentEntitySubclassId = parentInfo.parentEntitySubclassId; - final Object rootEmbeddable = rootEmbeddableGetters[parentEntitySubclassId].get( parentEntityInstance ); - loadedState[parentInfo.propertyIndex] = rootEmbeddablePropertyTypes[parentEntitySubclassId].deepCopy( - rootEmbeddable, - factory - ); + final Object rootEmbeddable = + rootEmbeddableGetters[parentEntitySubclassId] + .get( parentEntityInstance ); + loadedState[parentInfo.propertyIndex] = + rootEmbeddablePropertyTypes[parentEntitySubclassId] + .deepCopy( rootEmbeddable, factory ); } } } @@ -223,7 +218,8 @@ protected static String getRootEmbeddablePropertyName( @Override public String toString() { - return "BatchEntityInsideEmbeddableSelectFetchInitializer(" + LoggingHelper.toLoggableString( getNavigablePath() ) + ")"; + return "BatchEntityInsideEmbeddableSelectFetchInitializer(" + + toLoggableString( getNavigablePath() ) + ")"; } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/BatchEntitySelectFetchInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/BatchEntitySelectFetchInitializer.java index 12e5a2e557ff..610c5dcf21ae 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/BatchEntitySelectFetchInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/BatchEntitySelectFetchInitializer.java @@ -7,13 +7,8 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; -import java.util.Map; -import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.EntityKey; -import org.hibernate.engine.spi.PersistenceContext; -import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.internal.log.LoggingHelper; import org.hibernate.metamodel.mapping.AttributeMapping; import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping; import org.hibernate.persister.entity.EntityPersister; @@ -26,6 +21,8 @@ import org.hibernate.sql.results.jdbc.spi.RowProcessingState; import org.hibernate.type.Type; +import static org.hibernate.internal.log.LoggingHelper.toLoggableString; + public class BatchEntitySelectFetchInitializer extends AbstractBatchEntitySelectFetchInitializer { protected final AttributeMapping[] parentAttributes; protected final Setter referencedModelPartSetter; @@ -50,10 +47,11 @@ public BatchEntitySelectFetchInitializer( boolean affectedByFilter, AssemblerCreationState creationState) { super( parentAccess, referencedModelPart, fetchedNavigable, concreteDescriptor, keyResult, affectedByFilter, creationState ); - this.parentAttributes = getParentEntityAttributes( referencedModelPart.getAttributeName() ); - this.referencedModelPartSetter = referencedModelPart.getPropertyAccess().getSetter(); - this.referencedModelPartType = referencedModelPart.findContainingEntityMapping().getEntityPersister() - .getPropertyType( referencedModelPart.getAttributeName() ); + parentAttributes = getParentEntityAttributes( referencedModelPart.getAttributeName() ); + referencedModelPartSetter = referencedModelPart.getPropertyAccess().getSetter(); + referencedModelPartType = + referencedModelPart.findContainingEntityMapping().getEntityPersister() + .getPropertyType( referencedModelPart.getAttributeName() ); } @Override @@ -63,23 +61,25 @@ protected InitializerData createInitializerData(RowProcessingState rowProcessing @Override protected void registerResolutionListener(BatchEntitySelectFetchInitializerData data) { - final RowProcessingState rowProcessingState = data.getRowProcessingState(); - final InitializerData owningData = owningEntityInitializer.getData( rowProcessingState );HashMap> toBatchLoad = data.toBatchLoad; + final var rowProcessingState = data.getRowProcessingState(); + final var owningData = owningEntityInitializer.getData( rowProcessingState ); + var toBatchLoad = data.toBatchLoad; if ( toBatchLoad == null ) { toBatchLoad = data.toBatchLoad = new HashMap<>(); } // Always register the entity key for resolution - final List parentInfos = toBatchLoad.computeIfAbsent( data.entityKey, key -> new ArrayList<>() ); - final AttributeMapping parentAttribute; + final var parentInfos = toBatchLoad.computeIfAbsent( data.entityKey, key -> new ArrayList<>() ); // But only add the parent info if the parent entity is not already initialized - if ( owningData.getState() != State.INITIALIZED - && ( parentAttribute = parentAttributes[owningEntityInitializer.getConcreteDescriptor( owningData ).getSubclassId()] ) != null ) { - parentInfos.add( - new ParentInfo( - owningEntityInitializer.getTargetInstance( owningData ), - parentAttribute.getStateArrayPosition() - ) - ); + if ( owningData.getState() != State.INITIALIZED ) { + final var parentAttribute = + parentAttributes[owningEntityInitializer.getConcreteDescriptor( owningData ) + .getSubclassId()]; + if ( parentAttribute != null ) { + parentInfos.add( new ParentInfo( + owningEntityInitializer.getTargetInstance( owningData ), + parentAttribute.getStateArrayPosition() + ) ); + } } } @@ -96,24 +96,23 @@ public ParentInfo(Object parentInstance, int propertyIndex) { @Override public void endLoading(BatchEntitySelectFetchInitializerData data) { super.endLoading( data ); - final HashMap> toBatchLoad = data.toBatchLoad; + final var toBatchLoad = data.toBatchLoad; if ( toBatchLoad != null ) { - final SharedSessionContractImplementor session = data.getRowProcessingState().getSession(); - final PersistenceContext persistenceContext = session.getPersistenceContextInternal(); - for ( Map.Entry> entry : toBatchLoad.entrySet() ) { - final EntityKey entityKey = entry.getKey(); - final List parentInfos = entry.getValue(); + final var session = data.getRowProcessingState().getSession(); + final var factory = session.getFactory(); + final var persistenceContext = session.getPersistenceContextInternal(); + for ( var entry : toBatchLoad.entrySet() ) { + final var entityKey = entry.getKey(); + final var parentInfos = entry.getValue(); final Object instance = loadInstance( entityKey, toOneMapping, affectedByFilter, session ); - for ( ParentInfo parentInfo : parentInfos ) { + for ( var parentInfo : parentInfos ) { final Object parentInstance = parentInfo.parentInstance; - final EntityEntry entityEntry = persistenceContext.getEntry( parentInstance ); + final var entityEntry = persistenceContext.getEntry( parentInstance ); referencedModelPartSetter.set( parentInstance, instance ); - final Object[] loadedState = entityEntry.getLoadedState(); + final var loadedState = entityEntry.getLoadedState(); if ( loadedState != null ) { - loadedState[parentInfo.propertyIndex] = referencedModelPartType.deepCopy( - instance, - session.getFactory() - ); + loadedState[parentInfo.propertyIndex] = + referencedModelPartType.deepCopy( instance, factory ); } } } @@ -123,7 +122,8 @@ public void endLoading(BatchEntitySelectFetchInitializerData data) { @Override public String toString() { - return "BatchEntitySelectFetchInitializer(" + LoggingHelper.toLoggableString( getNavigablePath() ) + ")"; + return "BatchEntitySelectFetchInitializer(" + + toLoggableString( getNavigablePath() ) + ")"; } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/BatchInitializeEntitySelectFetchInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/BatchInitializeEntitySelectFetchInitializer.java index dd8569529f25..3618bb134bce 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/BatchInitializeEntitySelectFetchInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/BatchInitializeEntitySelectFetchInitializer.java @@ -7,8 +7,6 @@ import java.util.HashSet; import org.hibernate.engine.spi.EntityKey; -import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.internal.log.LoggingHelper; import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.spi.NavigablePath; @@ -18,6 +16,8 @@ import org.hibernate.sql.results.graph.InitializerParent; import org.hibernate.sql.results.jdbc.spi.RowProcessingState; +import static org.hibernate.internal.log.LoggingHelper.toLoggableString; + /** * Loads entities from the persistence context or creates proxies if not found there, * and initializes all proxies in a batch. @@ -59,27 +59,26 @@ protected void registerResolutionListener(BatchInitializeEntitySelectFetchInitia protected void registerToBatchFetchQueue(BatchInitializeEntitySelectFetchInitializerData data) { super.registerToBatchFetchQueue( data ); // Force creating a proxy - data.setInstance( data.getRowProcessingState().getSession().internalLoad( - data.entityKey.getEntityName(), - data.entityKey.getIdentifier(), - false, - false - ) ); - HashSet toBatchLoad = data.toBatchLoad; + final var entityKey = data.entityKey; + final Object instance = + data.getRowProcessingState().getSession() + .internalLoad( entityKey.getEntityName(), entityKey.getIdentifier(), false, false ); + data.setInstance( instance ); + var toBatchLoad = data.toBatchLoad; if ( toBatchLoad == null ) { toBatchLoad = data.toBatchLoad = new HashSet<>(); } - toBatchLoad.add( data.entityKey ); + toBatchLoad.add( entityKey ); } @Override public void endLoading(BatchInitializeEntitySelectFetchInitializerData data) { super.endLoading( data ); - final HashSet toBatchLoad = data.toBatchLoad; - if ( toBatchLoad != null ) { - final SharedSessionContractImplementor session = data.getRowProcessingState().getSession(); - for ( EntityKey key : toBatchLoad ) { - loadInstance( key, toOneMapping, affectedByFilter, session ); + final var keysToBatchLoad = data.toBatchLoad; + if ( keysToBatchLoad != null ) { + final var session = data.getRowProcessingState().getSession(); + for ( var entityKey : keysToBatchLoad ) { + loadInstance( entityKey, toOneMapping, affectedByFilter, session ); } data.toBatchLoad = null; } @@ -87,7 +86,8 @@ public void endLoading(BatchInitializeEntitySelectFetchInitializerData data) { @Override public String toString() { - return "BatchInitializeEntitySelectFetchInitializer(" + LoggingHelper.toLoggableString( getNavigablePath() ) + ")"; + return "BatchInitializeEntitySelectFetchInitializer(" + + toLoggableString( getNavigablePath() ) + ")"; } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/DiscriminatedEntityInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/DiscriminatedEntityInitializer.java index ba21c6d7b458..33872753fa4f 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/DiscriminatedEntityInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/DiscriminatedEntityInitializer.java @@ -9,14 +9,9 @@ import org.hibernate.Hibernate; import org.hibernate.engine.spi.EntityHolder; import org.hibernate.engine.spi.EntityKey; -import org.hibernate.engine.spi.PersistenceContext; -import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.internal.log.LoggingHelper; -import org.hibernate.metamodel.mapping.AttributeMapping; import org.hibernate.metamodel.mapping.DiscriminatedAssociationModelPart; import org.hibernate.metamodel.mapping.ModelPart; import org.hibernate.persister.entity.EntityPersister; -import org.hibernate.proxy.LazyInitializer; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.results.graph.AssemblerCreationState; import org.hibernate.sql.results.graph.DomainResultAssembler; @@ -30,6 +25,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; +import static org.hibernate.internal.log.LoggingHelper.toLoggableString; import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer; /** @@ -73,20 +69,15 @@ public DiscriminatedEntityInitializer( this.parent = parent; this.fetchedPart = fetchedPart; this.navigablePath = fetchedNavigable; - this.isPartOfKey = Initializer.isPartOfKey( fetchedNavigable, parent ); - this.discriminatorValueAssembler = discriminatorFetch.createAssembler( this, creationState ); - this.keyValueAssembler = keyFetch.createAssembler( this, creationState ); this.eager = eager; this.resultInitializer = resultInitializer; - final Initializer initializer = keyValueAssembler.getInitializer(); - if ( initializer == null ) { - this.keyIsEager = false; - this.hasLazySubInitializer = false; - } - else { - this.keyIsEager = initializer.isEager(); - this.hasLazySubInitializer = !initializer.isEager() || initializer.hasLazySubInitializers(); - } + + isPartOfKey = Initializer.isPartOfKey( fetchedNavigable, parent ); + discriminatorValueAssembler = discriminatorFetch.createAssembler( this, creationState ); + keyValueAssembler = keyFetch.createAssembler( this, creationState ); + + keyIsEager = keyValueAssembler.isEager(); + hasLazySubInitializer = keyValueAssembler.hasLazySubInitializers(); } @Override @@ -110,33 +101,33 @@ public NavigablePath getNavigablePath() { @Override public void resolveKey(DiscriminatedEntityInitializerData data) { - if ( data.getState() != State.UNINITIALIZED ) { - return; - } - - // resolve the key and the discriminator, and then use those to load the indicated entity - - final RowProcessingState rowProcessingState = data.getRowProcessingState(); - final Object discriminatorValue = discriminatorValueAssembler.assemble( rowProcessingState ); + if ( data.getState() == State.UNINITIALIZED ) { + // resolve the key and the discriminator, and then use those to load the indicated entity - if ( discriminatorValue == null ) { - data.setState( State.MISSING ); - data.concreteDescriptor = null; - data.entityIdentifier = null; - data.setInstance( null ); - // null association - assert keyValueAssembler.assemble( rowProcessingState ) == null; - } - else { - data.setState( State.KEY_RESOLVED ); - data.concreteDescriptor = fetchedPart.resolveDiscriminatorValue( discriminatorValue ).getEntityPersister(); - data.entityIdentifier = keyValueAssembler.assemble( rowProcessingState ); + final var rowProcessingState = data.getRowProcessingState(); + final Object discriminatorValue = + discriminatorValueAssembler.assemble( rowProcessingState ); + if ( discriminatorValue == null ) { + data.setState( State.MISSING ); + data.concreteDescriptor = null; + data.entityIdentifier = null; + data.setInstance( null ); + // null association + assert keyValueAssembler.assemble( rowProcessingState ) == null; + } + else { + data.setState( State.KEY_RESOLVED ); + data.concreteDescriptor = + fetchedPart.resolveDiscriminatorValue( discriminatorValue ) + .getEntityPersister(); + data.entityIdentifier = keyValueAssembler.assemble( rowProcessingState ); + } } } @Override public void resolveState(DiscriminatedEntityInitializerData data) { - final RowProcessingState rowProcessingState = data.getRowProcessingState(); + final var rowProcessingState = data.getRowProcessingState(); discriminatorValueAssembler.resolveState( rowProcessingState ); keyValueAssembler.resolveState( rowProcessingState ); } @@ -148,7 +139,7 @@ public void resolveFromPreviousRow(DiscriminatedEntityInitializerData data) { data.setState( State.MISSING ); } else { - final Initializer initializer = keyValueAssembler.getInitializer(); + final var initializer = keyValueAssembler.getInitializer(); if ( initializer != null ) { initializer.resolveFromPreviousRow( data.getRowProcessingState() ); } @@ -159,43 +150,56 @@ public void resolveFromPreviousRow(DiscriminatedEntityInitializerData data) { @Override public void resolveInstance(DiscriminatedEntityInitializerData data) { - if ( data.getState() != State.KEY_RESOLVED ) { - return; + if ( data.getState() == State.KEY_RESOLVED ) { + data.setState( State.INITIALIZED ); + final var session = data.getRowProcessingState().getSession(); + final Object identifier = data.entityIdentifier; + final var concreteDescriptor = data.concreteDescriptor; + final var entityKey = new EntityKey( identifier, concreteDescriptor ); + final var persistenceContext = session.getPersistenceContextInternal(); + final var holder = persistenceContext.getEntityHolder( entityKey ); + final Object instance; + if ( holder != null ) { + instance = holder.getEntity(); + data.setInstance( instance ); + } + else { + instance = null; + } + if ( !isResolved( holder, instance ) ) { + data.setInstance( session.internalLoad( + concreteDescriptor.getEntityName(), + identifier, + eager, + // should not be null since we checked already. null would indicate bad data (ala, not-found handling) + false + ) ); + } } + } - data.setState( State.INITIALIZED ); - - final SharedSessionContractImplementor session = data.getRowProcessingState().getSession(); - final EntityKey entityKey = new EntityKey( data.entityIdentifier, data.concreteDescriptor ); - - final PersistenceContext persistenceContext = session.getPersistenceContextInternal(); - final EntityHolder holder = persistenceContext.getEntityHolder( entityKey ); - if ( holder != null ) { - final Object instance = holder.getEntity(); - data.setInstance( instance ); - if ( holder.getEntityInitializer() == null ) { - if ( instance != null && Hibernate.isInitialized( instance ) ) { - return; - } + private boolean isResolved(EntityHolder holder, Object instance) { + if ( holder == null ) { + return false; + } + else { + final var initializer = holder.getEntityInitializer(); + if ( initializer == null ) { + return instance != null && Hibernate.isInitialized( instance ); } - else if ( holder.getEntityInitializer() != this ) { + else if ( initializer != this ) { // the entity is already being loaded elsewhere - return; + return true; } else if ( instance == null ) { // todo: maybe mark this as resolved instead? assert holder.getProxy() == null : "How to handle this case?"; - return; + return true; + } + else { + return false; } } - - data.setInstance( session.internalLoad( - data.concreteDescriptor.getEntityName(), - data.entityIdentifier, - eager, - // should not be null since we checked already. null would indicate bad data (ala, not-found handling) - false - ) ); } @Override @@ -207,67 +211,80 @@ public void resolveInstance(Object instance, DiscriminatedEntityInitializerData data.setInstance( null ); } else { - final RowProcessingState rowProcessingState = data.getRowProcessingState(); - final LazyInitializer lazyInitializer = extractLazyInitializer( instance ); - if ( lazyInitializer == null ) { - data.setState( State.INITIALIZED ); - if ( keyIsEager ) { - final SharedSessionContractImplementor session = rowProcessingState.getSession(); - data.concreteDescriptor = session.getEntityPersister( null, instance ); - data.entityIdentifier = data.concreteDescriptor.getIdentifier( instance, session ); - } - } - else if ( lazyInitializer.isUninitialized() ) { - data.setState( eager ? State.RESOLVED : State.INITIALIZED ); - if ( keyIsEager ) { - // Read the discriminator from the result set if necessary - final Object discriminatorValue = discriminatorValueAssembler.assemble( rowProcessingState ); - data.concreteDescriptor = fetchedPart.resolveDiscriminatorValue( discriminatorValue ).getEntityPersister(); - data.entityIdentifier = lazyInitializer.getInternalIdentifier(); - } - } - else { - data.setState( State.INITIALIZED ); - if ( keyIsEager ) { - data.concreteDescriptor = rowProcessingState.getSession().getEntityPersister( null, lazyInitializer.getImplementation() ); - data.entityIdentifier = lazyInitializer.getInternalIdentifier(); - } - } - data.setInstance( instance ); + resolve( instance, data ); + final var rowProcessingState = data.getRowProcessingState(); if ( keyIsEager ) { - final Initializer initializer = keyValueAssembler.getInitializer(); + final var initializer = keyValueAssembler.getInitializer(); assert initializer != null; initializer.resolveInstance( data.entityIdentifier, rowProcessingState ); } else if ( rowProcessingState.needsResolveState() ) { - // Resolve the state of the identifier if result caching is enabled and this is not a query cache hit + // Resolve the state of the identifier if result caching is enabled, and this is not a query cache hit discriminatorValueAssembler.resolveState( rowProcessingState ); keyValueAssembler.resolveState( rowProcessingState ); } } } + private void resolve( + Object instance, + DiscriminatedEntityInitializerData data) { + final var rowProcessingState = data.getRowProcessingState(); + final var session = rowProcessingState.getSession(); + final var lazyInitializer = extractLazyInitializer( instance ); + if ( lazyInitializer == null ) { + data.setState( State.INITIALIZED ); + if ( keyIsEager ) { + data.concreteDescriptor = session.getEntityPersister( null, instance ); + data.entityIdentifier = data.concreteDescriptor.getIdentifier( instance, session ); + } + } + else if ( lazyInitializer.isUninitialized() ) { + data.setState( eager ? State.RESOLVED : State.INITIALIZED ); + if ( keyIsEager ) { + // Read the discriminator from the result set if necessary + final Object discriminatorValue = + discriminatorValueAssembler.assemble( rowProcessingState ); + data.concreteDescriptor = + fetchedPart.resolveDiscriminatorValue( discriminatorValue ) + .getEntityPersister(); + data.entityIdentifier = lazyInitializer.getInternalIdentifier(); + } + } + else { + data.setState( State.INITIALIZED ); + if ( keyIsEager ) { + data.concreteDescriptor = + session.getEntityPersister( null, lazyInitializer.getImplementation() ); + data.entityIdentifier = lazyInitializer.getInternalIdentifier(); + } + } + data.setInstance( instance ); + } + @Override public void initializeInstance(DiscriminatedEntityInitializerData data) { - if ( data.getState() != State.RESOLVED ) { - return; + if ( data.getState() == State.RESOLVED ) { + data.setState( State.INITIALIZED ); + data.setInstance( data.getRowProcessingState().getSession() + .internalLoad( + data.concreteDescriptor.getEntityName(), + data.entityIdentifier, + eager, + // should not be null since we checked already. + // null would indicate bad data (ala, not-found handling) + false + ) ); } - data.setState( State.INITIALIZED ); - data.setInstance( data.getRowProcessingState().getSession().internalLoad( - data.concreteDescriptor.getEntityName(), - data.entityIdentifier, - eager, - // should not be null since we checked already. null would indicate bad data (ala, not-found handling) - false - ) ); } @Override public void initializeInstanceFromParent(Object parentInstance, DiscriminatedEntityInitializerData data) { - final AttributeMapping attributeMapping = getInitializedPart().asAttributeMapping(); - final Object instance = attributeMapping != null - ? attributeMapping.getValue( parentInstance ) - : parentInstance; + final var attributeMapping = getInitializedPart().asAttributeMapping(); + final Object instance = + attributeMapping != null + ? attributeMapping.getValue( parentInstance ) + : parentInstance; if ( instance == null ) { data.setState( State.MISSING ); data.setInstance( null ); @@ -288,7 +305,7 @@ public void initializeInstanceFromParent(Object parentInstance, DiscriminatedEnt @Override protected void forEachSubInitializer(BiConsumer, RowProcessingState> consumer, InitializerData data) { - final Initializer initializer = keyValueAssembler.getInitializer(); + final var initializer = keyValueAssembler.getInitializer(); if ( initializer != null ) { consumer.accept( initializer, data.getRowProcessingState() ); } @@ -331,7 +348,8 @@ public boolean isResultInitializer() { @Override public String toString() { - return "DiscriminatedEntityInitializer(" + LoggingHelper.toLoggableString( getNavigablePath() ) + ")"; + return "DiscriminatedEntityInitializer(" + + toLoggableString( getNavigablePath() ) + ")"; } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityDelayedFetchInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityDelayedFetchInitializer.java index 92441140cc40..6dd33d918a6d 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityDelayedFetchInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityDelayedFetchInitializer.java @@ -9,21 +9,14 @@ import org.hibernate.FetchNotFoundException; import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor; import org.hibernate.engine.internal.ManagedTypeHelper; -import org.hibernate.engine.spi.EntityHolder; import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.EntityUniqueKey; -import org.hibernate.engine.spi.PersistenceContext; import org.hibernate.engine.spi.PersistentAttributeInterceptable; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.graph.GraphSemantic; -import org.hibernate.graph.spi.AppliedGraph; -import org.hibernate.graph.spi.AttributeNodeImplementor; -import org.hibernate.internal.log.LoggingHelper; import org.hibernate.metamodel.mapping.ModelPart; import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping; import org.hibernate.persister.entity.EntityPersister; -import org.hibernate.proxy.HibernateProxy; -import org.hibernate.proxy.LazyInitializer; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.results.graph.AssemblerCreationState; import org.hibernate.sql.results.graph.DomainResult; @@ -41,6 +34,8 @@ import org.checkerframework.checker.nullness.qual.Nullable; import static org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer.UNFETCHED_PROPERTY; +import static org.hibernate.internal.log.LoggingHelper.toLoggableString; +import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer; import static org.hibernate.sql.results.graph.entity.internal.EntityInitializerImpl.determineConcreteEntityDescriptor; /** @@ -79,26 +74,31 @@ public EntityDelayedFetchInitializer( @Nullable BasicFetch discriminatorResult, AssemblerCreationState creationState) { super( creationState ); - // associations marked with `@NotFound` are ALWAYS eagerly fetched, unless we're resolving the concrete type - assert !referencedModelPart.hasNotFoundAction() || referencedModelPart.getEntityMappingType().isConcreteProxy(); + // associations marked with '@NotFound' are ALWAYS eagerly fetched, + // unless we're resolving the concrete type + assert !referencedModelPart.hasNotFoundAction() + || referencedModelPart.getEntityMappingType().isConcreteProxy(); this.parent = parent; this.navigablePath = fetchedNavigable; - this.isPartOfKey = Initializer.isPartOfKey( fetchedNavigable, parent ); this.referencedModelPart = referencedModelPart; this.selectByUniqueKey = selectByUniqueKey; - this.identifierAssembler = keyResult.createResultAssembler( this, creationState ); - this.discriminatorAssembler = discriminatorResult == null - ? null - : (BasicResultAssembler) discriminatorResult.createResultAssembler( this, creationState ); - final Initializer initializer; - if ( identifierAssembler == null || ( initializer = identifierAssembler.getInitializer() ) == null ) { - this.keyIsEager = false; - this.hasLazySubInitializer = false; + + isPartOfKey = Initializer.isPartOfKey( fetchedNavigable, parent ); + identifierAssembler = keyResult.createResultAssembler( this, creationState ); + discriminatorAssembler = + discriminatorResult == null + ? null + : (BasicResultAssembler) + discriminatorResult.createResultAssembler( this, creationState ); + + if ( identifierAssembler == null ) { + keyIsEager = false; + hasLazySubInitializer = false; } else { - this.keyIsEager = initializer.isEager(); - this.hasLazySubInitializer = !initializer.isEager() || initializer.hasLazySubInitializers(); + keyIsEager = identifierAssembler.isEager(); + hasLazySubInitializer = identifierAssembler.hasLazySubInitializers(); } } @@ -124,7 +124,7 @@ public void resolveFromPreviousRow(EntityDelayedFetchInitializerData data) { data.setState( State.MISSING ); } else { - final Initializer initializer = identifierAssembler.getInitializer(); + final var initializer = identifierAssembler.getInitializer(); if ( initializer != null ) { initializer.resolveFromPreviousRow( data.getRowProcessingState() ); } @@ -135,145 +135,170 @@ public void resolveFromPreviousRow(EntityDelayedFetchInitializerData data) { @Override public void resolveInstance(EntityDelayedFetchInitializerData data) { - if ( data.getState() != State.KEY_RESOLVED ) { - return; - } - - // This initializer is done initializing, since this is only invoked for delayed or select initializers - data.setState( State.INITIALIZED ); + if ( data.getState() == State.KEY_RESOLVED ) { + // This initializer is done initializing, since this is only invoked for delayed or select initializers + data.setState( State.INITIALIZED ); - final RowProcessingState rowProcessingState = data.getRowProcessingState(); - data.entityIdentifier = identifierAssembler.assemble( rowProcessingState ); + final var rowProcessingState = data.getRowProcessingState(); + data.entityIdentifier = identifierAssembler.assemble( rowProcessingState ); - if ( data.entityIdentifier == null ) { - data.setInstance( null ); - data.setState( State.MISSING ); - } - else { - final SharedSessionContractImplementor session = rowProcessingState.getSession(); - - final EntityPersister entityPersister = getEntityDescriptor(); - final EntityPersister concreteDescriptor; - if ( discriminatorAssembler != null ) { - concreteDescriptor = determineConcreteEntityDescriptor( - rowProcessingState, - discriminatorAssembler, - entityPersister - ); - if ( concreteDescriptor == null ) { - // If we find no discriminator it means there's no entity in the target table - if ( !referencedModelPart.isOptional() ) { - throw new FetchNotFoundException( entityPersister.getEntityName(), data.entityIdentifier ); + if ( data.entityIdentifier == null ) { + data.setInstance( null ); + data.setState( State.MISSING ); + } + else { + final var entityPersister = getEntityDescriptor(); + final EntityPersister concreteDescriptor; + if ( discriminatorAssembler != null ) { + concreteDescriptor = determineConcreteEntityDescriptor( + rowProcessingState, + discriminatorAssembler, + entityPersister + ); + if ( concreteDescriptor == null ) { + // If we find no discriminator, it means there's no entity in the target table + if ( !referencedModelPart.isOptional() ) { + throw new FetchNotFoundException( entityPersister.getEntityName(), data.entityIdentifier ); + } + data.setInstance( null ); + data.setState( State.MISSING ); + return; } - data.setInstance( null ); - data.setState( State.MISSING ); - return; + } + else { + concreteDescriptor = entityPersister; + } + + if ( selectByUniqueKey ) { + data.setInstance( instanceWithUniqueKey( data, concreteDescriptor ) ); + } + else { + data.setInstance( instanceWithId( data, concreteDescriptor ) ); } } - else { - concreteDescriptor = entityPersister; + } + } + + private Object instanceWithId( + EntityDelayedFetchInitializerData data, + EntityPersister concreteDescriptor) { + final var rowProcessingState = data.getRowProcessingState(); + final var session = rowProcessingState.getSession(); + final var persistenceContext = session.getPersistenceContextInternal(); + + final var entityKey = new EntityKey( data.entityIdentifier, concreteDescriptor ); + final var holder = persistenceContext.getEntityHolder( entityKey ); + if ( holder != null && holder.getEntity() != null ) { + return persistenceContext.proxyFor( holder, concreteDescriptor ); + } + // For primary key-based mappings we only use bytecode-laziness if the attribute is optional, + // because the non-optionality implies that it is safe to have a proxy + else if ( referencedModelPart.isOptional() && referencedModelPart.isLazy() ) { + return UNFETCHED_PROPERTY; + } + else { + final Object instance = session.internalLoad( + concreteDescriptor.getEntityName(), + data.entityIdentifier, + false, + false + ); + final var lazyInitializer = extractLazyInitializer( instance ); + if ( lazyInitializer != null ) { + lazyInitializer.setUnwrap( + referencedModelPart.isUnwrapProxy() + && concreteDescriptor.isInstrumented() ); } + return instance; + } + } - final PersistenceContext persistenceContext = session.getPersistenceContextInternal(); - if ( selectByUniqueKey ) { - final String uniqueKeyPropertyName = referencedModelPart.getReferencedPropertyName(); - final Type uniqueKeyPropertyType = ( referencedModelPart.getReferencedPropertyName() == null ) ? - concreteDescriptor.getIdentifierType() : - session.getFactory().getRuntimeMetamodels() - .getReferencedPropertyType( - concreteDescriptor.getEntityName(), - uniqueKeyPropertyName - ); - - final EntityUniqueKey euk = new EntityUniqueKey( + private Object instanceWithUniqueKey( + EntityDelayedFetchInitializerData data, + EntityPersister concreteDescriptor) { + final var rowProcessingState = data.getRowProcessingState(); + final var session = rowProcessingState.getSession(); + final var persistenceContext = session.getPersistenceContextInternal(); + + final String uniqueKeyPropertyName = referencedModelPart.getReferencedPropertyName(); + final var entityUniqueKey = + new EntityUniqueKey( concreteDescriptor.getEntityName(), uniqueKeyPropertyName, data.entityIdentifier, - uniqueKeyPropertyType, + getUniqueKeyPropertyType( concreteDescriptor, session, uniqueKeyPropertyName ), session.getFactory() ); - Object instance = persistenceContext.getEntity( euk ); - if ( instance == null ) { - // For unique-key mappings, we always use bytecode-laziness if possible, - // because we can't generate a proxy based on the unique key yet - if ( referencedModelPart.isLazy() ) { - instance = UNFETCHED_PROPERTY; - } - else { - // Try to load a PersistentAttributeInterceptable. If we get one, we can add the lazy - // field to the interceptor. If we don't get one, we load the entity by unique key. - PersistentAttributeInterceptable persistentAttributeInterceptable = null; - if ( getParent().isEntityInitializer() && isLazyByGraph( rowProcessingState ) ) { - final Object resolvedInstance = - getParent().asEntityInitializer().getResolvedInstance( rowProcessingState ); - persistentAttributeInterceptable = - ManagedTypeHelper.asPersistentAttributeInterceptableOrNull( resolvedInstance ); - } - if ( persistentAttributeInterceptable != null ) { - final LazyAttributeLoadingInterceptor persistentAttributeInterceptor = (LazyAttributeLoadingInterceptor) persistentAttributeInterceptable.$$_hibernate_getInterceptor(); - persistentAttributeInterceptor.addLazyFieldByGraph( navigablePath.getLocalName() ); - instance = UNFETCHED_PROPERTY; - } - else { - instance = concreteDescriptor.loadByUniqueKey( - uniqueKeyPropertyName, - data.entityIdentifier, - session - ); - - // If the entity was not in the Persistence Context, but was found now, - // add it to the Persistence Context - if ( instance != null ) { - persistenceContext.addEntity( euk, instance ); - } - } - } - } - if ( instance != null ) { - instance = persistenceContext.proxyFor( instance ); - } - data.setInstance( instance ); + Object instance = persistenceContext.getEntity( entityUniqueKey ); + if ( instance == null ) { + // For unique-key mappings, we always use bytecode-laziness if possible, + // because we can't generate a proxy based on the unique key yet + if ( referencedModelPart.isLazy() ) { + instance = UNFETCHED_PROPERTY; } else { - final EntityKey entityKey = new EntityKey( data.entityIdentifier, concreteDescriptor ); - final EntityHolder holder = persistenceContext.getEntityHolder( entityKey ); - final Object instance; - if ( holder != null && holder.getEntity() != null ) { - instance = persistenceContext.proxyFor( holder, concreteDescriptor ); - } - // For primary key based mappings we only use bytecode-laziness if the attribute is optional, - // because the non-optionality implies that it is safe to have a proxy - else if ( referencedModelPart.isOptional() && referencedModelPart.isLazy() ) { + // Try to load a PersistentAttributeInterceptable. If we get one, we can add the lazy + // field to the interceptor. If we don't get one, we load the entity by unique key. + final var persistentAttributeInterceptable = + getPersistentAttributeInterceptable( rowProcessingState ); + if ( persistentAttributeInterceptable != null ) { + final var persistentAttributeInterceptor = + (LazyAttributeLoadingInterceptor) + persistentAttributeInterceptable.$$_hibernate_getInterceptor(); + persistentAttributeInterceptor.addLazyFieldByGraph( navigablePath.getLocalName() ); instance = UNFETCHED_PROPERTY; } else { - instance = session.internalLoad( - concreteDescriptor.getEntityName(), + instance = concreteDescriptor.loadByUniqueKey( + uniqueKeyPropertyName, data.entityIdentifier, - false, - false + session ); - final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( instance ); - if ( lazyInitializer != null ) { - lazyInitializer.setUnwrap( referencedModelPart.isUnwrapProxy() && concreteDescriptor.isInstrumented() ); + // If the entity was not in the Persistence Context, but was found now, + // add it to the Persistence Context + if ( instance != null ) { + persistenceContext.addEntity( entityUniqueKey, instance ); } } - data.setInstance( instance ); } } + if ( instance != null ) { + instance = persistenceContext.proxyFor( instance ); + } + return instance; + } + + private PersistentAttributeInterceptable getPersistentAttributeInterceptable(RowProcessingState rowProcessingState) { + if ( getParent().isEntityInitializer() && isLazyByGraph( rowProcessingState ) ) { + final Object resolvedInstance = + getParent().asEntityInitializer() + .getResolvedInstance( rowProcessingState ); + return ManagedTypeHelper.asPersistentAttributeInterceptableOrNull( resolvedInstance ); + } + else { + return null; + } + } + + private Type getUniqueKeyPropertyType(EntityPersister concreteDescriptor, SharedSessionContractImplementor session, String uniqueKeyPropertyName) { + return referencedModelPart.getReferencedPropertyName() == null + ? concreteDescriptor.getIdentifierType() + : session.getFactory().getRuntimeMetamodels() + .getReferencedPropertyType( concreteDescriptor.getEntityName(), uniqueKeyPropertyName ); } private boolean isLazyByGraph(RowProcessingState rowProcessingState) { - final AppliedGraph appliedGraph = rowProcessingState.getQueryOptions().getAppliedGraph(); + final var appliedGraph = rowProcessingState.getQueryOptions().getAppliedGraph(); if ( appliedGraph != null && appliedGraph.getSemantic() == GraphSemantic.FETCH ) { - final AttributeNodeImplementor attributeNode = - appliedGraph.getGraph().findAttributeNode( navigablePath.getLocalName() ); + final var attributeNode = appliedGraph.getGraph().findAttributeNode( navigablePath.getLocalName() ); return attributeNode == null || attributeNode.getAttributeDescriptor() != getInitializedPart().asAttributeMapping(); } - return false; + else { + return false; + } } @Override @@ -287,15 +312,15 @@ public void resolveInstance(Object instance, EntityDelayedFetchInitializerData d // This initializer is done initializing, since this is only invoked for delayed or select initializers data.setState( State.INITIALIZED ); data.setInstance( instance ); - final RowProcessingState rowProcessingState = data.getRowProcessingState(); + final var rowProcessingState = data.getRowProcessingState(); if ( keyIsEager ) { data.entityIdentifier = getEntityDescriptor().getIdentifier( instance, rowProcessingState.getSession() ); - final Initializer initializer = identifierAssembler.getInitializer(); + final var initializer = identifierAssembler.getInitializer(); assert initializer != null; initializer.resolveInstance( data.entityIdentifier, rowProcessingState ); } else if ( rowProcessingState.needsResolveState() ) { - // Resolve the state of the identifier if result caching is enabled and this is not a query cache hit + // Resolve the state of the identifier if result caching is enabled, and this is not a query cache hit identifierAssembler.resolveState( rowProcessingState ); } } @@ -303,7 +328,7 @@ else if ( rowProcessingState.needsResolveState() ) { @Override protected void forEachSubInitializer(BiConsumer, RowProcessingState> consumer, InitializerData data) { - final Initializer initializer = identifierAssembler.getInitializer(); + final var initializer = identifierAssembler.getInitializer(); if ( initializer != null ) { consumer.accept( initializer, data.getRowProcessingState() ); } @@ -346,7 +371,7 @@ public EntityPersister getConcreteDescriptor(EntityDelayedFetchInitializerData d @Override public void resolveState(EntityDelayedFetchInitializerData data) { - final RowProcessingState rowProcessingState = data.getRowProcessingState(); + final var rowProcessingState = data.getRowProcessingState(); identifierAssembler.resolveState( rowProcessingState ); if ( discriminatorAssembler != null ) { discriminatorAssembler.resolveState( rowProcessingState ); @@ -360,7 +385,8 @@ public void resolveState(EntityDelayedFetchInitializerData data) { @Override public String toString() { - return "EntityDelayedFetchInitializer(" + LoggingHelper.toLoggableString( navigablePath ) + ")"; + return "EntityDelayedFetchInitializer(" + + toLoggableString( navigablePath ) + ")"; } //######################### diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityInitializerImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityInitializerImpl.java index a5c6e9f514f6..dfb0ad123fe7 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityInitializerImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityInitializerImpl.java @@ -6,7 +6,6 @@ import java.util.Arrays; import java.util.BitSet; -import java.util.Collection; import java.util.concurrent.ConcurrentHashMap; import java.util.function.BiConsumer; @@ -22,7 +21,6 @@ import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor; import org.hibernate.cache.spi.access.AccessType; import org.hibernate.cache.spi.access.EntityDataAccess; -import org.hibernate.cache.spi.entry.CacheEntry; import org.hibernate.engine.internal.ForeignKeys; import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.EntityHolder; @@ -30,51 +28,34 @@ import org.hibernate.engine.spi.EntityUniqueKey; import org.hibernate.engine.spi.PersistenceContext; import org.hibernate.engine.spi.PersistentAttributeInterceptor; -import org.hibernate.engine.spi.SessionEventListenerManager; -import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.Status; import org.hibernate.event.monitor.spi.EventMonitor; -import org.hibernate.event.monitor.spi.DiagnosticEvent; -import org.hibernate.event.spi.PreLoadEvent; import org.hibernate.event.spi.PreLoadEventListener; -import org.hibernate.internal.log.LoggingHelper; import org.hibernate.internal.util.ImmutableBitSet; -import org.hibernate.metamodel.mapping.AttributeMapping; -import org.hibernate.metamodel.mapping.AttributeMetadata; import org.hibernate.metamodel.mapping.CompositeIdentifierMapping; -import org.hibernate.metamodel.mapping.DiscriminatorValueDetails; -import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping; -import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.EntityValuedModelPart; -import org.hibernate.metamodel.mapping.EntityVersionMapping; import org.hibernate.metamodel.mapping.ModelPart; import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping; import org.hibernate.persister.entity.EntityPersister; -import org.hibernate.persister.entity.UniqueKeyEntry; import org.hibernate.property.access.internal.PropertyAccessStrategyBackRefImpl; -import org.hibernate.proxy.LazyInitializer; import org.hibernate.proxy.map.MapProxy; import org.hibernate.spi.NavigablePath; -import org.hibernate.sql.exec.spi.ExecutionContext; import org.hibernate.sql.results.graph.AssemblerCreationState; import org.hibernate.sql.results.graph.DomainResult; import org.hibernate.sql.results.graph.DomainResultAssembler; import org.hibernate.sql.results.graph.Fetch; -import org.hibernate.sql.results.graph.FetchParent; import org.hibernate.sql.results.graph.Initializer; import org.hibernate.sql.results.graph.InitializerData; import org.hibernate.sql.results.graph.InitializerParent; import org.hibernate.sql.results.graph.basic.BasicResultAssembler; import org.hibernate.sql.results.graph.collection.internal.AbstractImmediateCollectionInitializer; -import org.hibernate.sql.results.graph.embeddable.EmbeddableInitializer; import org.hibernate.sql.results.graph.entity.EntityInitializer; import org.hibernate.sql.results.graph.entity.EntityResultGraphNode; import org.hibernate.sql.results.graph.internal.AbstractInitializer; import org.hibernate.sql.results.internal.NullValueAssembler; import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingOptions; import org.hibernate.sql.results.jdbc.spi.RowProcessingState; -import org.hibernate.stat.spi.StatisticsImplementor; import org.hibernate.type.ManyToOneType; import org.hibernate.type.Type; import org.hibernate.type.descriptor.java.MutabilityPlan; @@ -85,6 +66,7 @@ import static org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer.UNFETCHED_PROPERTY; import static org.hibernate.engine.internal.ManagedTypeHelper.asPersistentAttributeInterceptable; import static org.hibernate.engine.internal.ManagedTypeHelper.isPersistentAttributeInterceptable; +import static org.hibernate.internal.log.LoggingHelper.toLoggableString; import static org.hibernate.internal.util.NullnessUtil.castNonNull; import static org.hibernate.loader.internal.CacheLoadHelper.loadFromSecondLevelCache; import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer; @@ -92,10 +74,11 @@ /** * @author Andrea Boriero */ -public class EntityInitializerImpl extends AbstractInitializer +public class EntityInitializerImpl + extends AbstractInitializer implements EntityInitializer { - // NOTE : even though we only keep the EntityDescriptor here, rather than EntityResultGraphNode + // NOTE: even though we only keep the EntityDescriptor here, rather than EntityResultGraphNode, // the "scope" of this initializer is a specific EntityReference. // // The full EntityResultGraphNode is simply not needed here, and so we just keep @@ -158,16 +141,18 @@ public static class EntityInitializerData extends InitializerData { public EntityInitializerData(EntityInitializerImpl initializer, RowProcessingState rowProcessingState) { super( rowProcessingState ); - final EntityPersister entityDescriptor = initializer.entityDescriptor; + final var entityDescriptor = initializer.entityDescriptor; shallowCached = rowProcessingState.isQueryCacheHit() && entityDescriptor.useShallowQueryCacheLayout(); lockMode = rowProcessingState.determineEffectiveLockMode( initializer.sourceAlias ); if ( initializer.isResultInitializer() ) { uniqueKeyAttributePath = rowProcessingState.getEntityUniqueKeyAttributePath(); - uniqueKeyPropertyTypes = uniqueKeyAttributePath != null - ? initializer.getParentEntityAttributeTypes( uniqueKeyAttributePath ) - : null; - canUseEmbeddedIdentifierInstanceAsEntity = rowProcessingState.getEntityId() != null - && initializer.couldUseEmbeddedIdentifierInstanceAsEntity; + uniqueKeyPropertyTypes = + uniqueKeyAttributePath != null + ? initializer.getParentEntityAttributeTypes( uniqueKeyAttributePath ) + : null; + canUseEmbeddedIdentifierInstanceAsEntity = + rowProcessingState.getEntityId() != null + && initializer.couldUseEmbeddedIdentifierInstanceAsEntity; } else { uniqueKeyAttributePath = null; @@ -223,27 +208,28 @@ public EntityInitializerImpl( boolean isResultInitializer, AssemblerCreationState creationState) { super( creationState ); + this.sourceAlias = sourceAlias; + this.parent = parent; + this.isResultInitializer = isResultInitializer; referencedModelPart = resultDescriptor.getEntityValuedModelPart(); entityDescriptor = (EntityPersister) referencedModelPart.getEntityMappingType(); final String rootEntityName = entityDescriptor.getRootEntityName(); - rootEntityDescriptor = rootEntityName == null || rootEntityName.equals( entityDescriptor.getEntityName() ) - ? entityDescriptor - : entityDescriptor.getRootEntityDescriptor().getEntityPersister(); + rootEntityDescriptor = + rootEntityName == null || rootEntityName.equals( entityDescriptor.getEntityName() ) + ? entityDescriptor + : entityDescriptor.getRootEntityDescriptor().getEntityPersister(); keyTypeForEqualsHashCode = entityDescriptor.getIdentifierType().getTypeForEqualsHashCode(); // The id can only be the entity instance if this is a non-aggregated id that has no containing class couldUseEmbeddedIdentifierInstanceAsEntity = entityDescriptor.getIdentifierMapping() instanceof CompositeIdentifierMapping composite && !composite.hasContainingClass(); - this.navigablePath = resultDescriptor.getNavigablePath(); - this.sourceAlias = sourceAlias; - this.parent = parent; - this.isResultInitializer = isResultInitializer; - this.isPartOfKey = Initializer.isPartOfKey( navigablePath, parent ); + navigablePath = resultDescriptor.getNavigablePath(); + isPartOfKey = Initializer.isPartOfKey( navigablePath, parent ); // If the parent already has previous row reuse enabled, we can skip that here - this.previousRowReuse = !isPreviousRowReuse( parent ) && ( + previousRowReuse = !isPreviousRowReuse( parent ) && ( // If this entity domain result contains a collection join fetch, this usually means that the entity data is // duplicate in the result data for every collection element. Since collections usually have more than one element, // optimizing the resolving of the entity data is very beneficial. @@ -259,19 +245,21 @@ public EntityInitializerImpl( } else { identifierAssembler = identifierFetch.createAssembler( this, creationState ); - final Initializer initializer = identifierAssembler.getInitializer(); + final var initializer = identifierAssembler.getInitializer(); hasKeyManyToOne = initializer != null && initializer.isLazyCapable(); } assert entityDescriptor.hasSubclasses() == (discriminatorFetch != null) : "Discriminator should only be fetched if the entity has subclasses"; - discriminatorAssembler = discriminatorFetch != null - ? (BasicResultAssembler) discriminatorFetch.createAssembler( this, creationState ) - : null; + discriminatorAssembler = + discriminatorFetch == null + ? null + : (BasicResultAssembler) + discriminatorFetch.createAssembler( this, creationState ); - final EntityVersionMapping versionMapping = entityDescriptor.getVersionMapping(); + final var versionMapping = entityDescriptor.getVersionMapping(); if ( versionMapping != null ) { - final Fetch versionFetch = resultDescriptor.findFetch( versionMapping ); + final var versionFetch = resultDescriptor.findFetch( versionMapping ); // If there is a version mapping, there must be a fetch for it assert versionFetch != null; versionAssembler = versionFetch.createAssembler( this, creationState ); @@ -280,45 +268,48 @@ public EntityInitializerImpl( versionAssembler = null; } - rowIdAssembler = rowIdResult != null - ? rowIdResult.createResultAssembler( this, creationState ) - : null; + rowIdAssembler = + rowIdResult == null + ? null : + rowIdResult.createResultAssembler( this, creationState ); final int fetchableCount = entityDescriptor.getNumberOfFetchables(); - final Collection subMappingTypes = rootEntityDescriptor.getSubMappingTypes(); - final DomainResultAssembler[][] assemblers = new DomainResultAssembler[subMappingTypes.size() + 1][]; - final Initializer[] allInitializers = new Initializer[fetchableCount]; - final Initializer[][] subInitializers = new Initializer[subMappingTypes.size() + 1][]; - final Initializer[][] eagerSubInitializers = new Initializer[subMappingTypes.size() + 1][]; - final Initializer[][] collectionContainingSubInitializers = new Initializer[subMappingTypes.size() + 1][]; - final BitSet[] lazySets = new BitSet[subMappingTypes.size() + 1]; - final BitSet[] maybeLazySets = new BitSet[subMappingTypes.size() + 1]; - final MutabilityPlan[][] updatableAttributeMutabilityPlans = new MutabilityPlan[subMappingTypes.size() + 1][]; + final var subMappingTypes = rootEntityDescriptor.getSubMappingTypes(); + final var assemblers = new DomainResultAssembler[subMappingTypes.size() + 1][]; + final var allInitializers = new Initializer[fetchableCount]; + final var subInitializers = new Initializer[subMappingTypes.size() + 1][]; + final var eagerSubInitializers = new Initializer[subMappingTypes.size() + 1][]; + final var collectionContainingSubInitializers = new Initializer[subMappingTypes.size() + 1][]; + final var lazySets = new BitSet[subMappingTypes.size() + 1]; + final var maybeLazySets = new BitSet[subMappingTypes.size() + 1]; + final var updatableAttributeMutabilityPlans = new MutabilityPlan[subMappingTypes.size() + 1][]; assemblers[rootEntityDescriptor.getSubclassId()] = new DomainResultAssembler[rootEntityDescriptor.getNumberOfFetchables()]; updatableAttributeMutabilityPlans[rootEntityDescriptor.getSubclassId()] = new MutabilityPlan[rootEntityDescriptor.getNumberOfAttributeMappings()]; - for ( EntityMappingType subMappingType : subMappingTypes ) { - assemblers[subMappingType.getSubclassId()] = + for ( var subMappingType : subMappingTypes ) { + final int subclassId = subMappingType.getSubclassId(); + assemblers[subclassId] = new DomainResultAssembler[subMappingType.getNumberOfFetchables()]; - updatableAttributeMutabilityPlans[subMappingType.getSubclassId()] = + updatableAttributeMutabilityPlans[subclassId] = new MutabilityPlan[subMappingType.getNumberOfAttributeMappings()]; } boolean hasLazySubInitializers = false; for ( int i = 0; i < fetchableCount; i++ ) { - final AttributeMapping attributeMapping = entityDescriptor.getFetchable( i ).asAttributeMapping(); - final Fetch fetch = resultDescriptor.findFetch( attributeMapping ); - final DomainResultAssembler stateAssembler = fetch == null - ? new NullValueAssembler<>( attributeMapping.getMappedType().getMappedJavaType() ) - : fetch.createAssembler( this, creationState ); + final var attributeMapping = entityDescriptor.getFetchable( i ).asAttributeMapping(); + final var fetch = resultDescriptor.findFetch( attributeMapping ); + final var stateAssembler = + fetch == null + ? new NullValueAssembler<>( attributeMapping.getMappedType().getMappedJavaType() ) + : fetch.createAssembler( this, creationState ); final int stateArrayPosition = attributeMapping.getStateArrayPosition(); - final EntityMappingType declaringType = attributeMapping.getDeclaringType().asEntityMappingType(); + final var declaringType = attributeMapping.getDeclaringType().asEntityMappingType(); final int subclassId = declaringType.getSubclassId(); - final Initializer subInitializer = stateAssembler.getInitializer(); + final var subInitializer = stateAssembler.getInitializer(); if ( subInitializer != null ) { allInitializers[i] = subInitializer; if ( subInitializers[subclassId] == null ) { @@ -336,8 +327,8 @@ public EntityInitializerImpl( hasLazySubInitializers = true; } assert fetch != null; - final FetchParent fetchParent; - if ( ( fetchParent = fetch.asFetchParent() ) != null && fetchParent.containsCollectionFetches() + final var fetchParent = fetch.asFetchParent(); + if ( fetchParent != null && fetchParent.containsCollectionFetches() || subInitializer.isCollectionInitializer() ) { collectionContainingSubInitializers[subclassId][stateArrayPosition] = subInitializer; } @@ -351,11 +342,11 @@ public EntityInitializerImpl( } assemblers[subclassId][stateArrayPosition] = stateAssembler; - final AttributeMetadata attributeMetadata = attributeMapping.getAttributeMetadata(); + final var attributeMetadata = attributeMapping.getAttributeMetadata(); if ( attributeMetadata.isUpdatable() ) { updatableAttributeMutabilityPlans[subclassId][stateArrayPosition] = attributeMetadata.getMutabilityPlan(); } - for ( EntityMappingType subMappingType : declaringType.getSubMappingTypes() ) { + for ( var subMappingType : declaringType.getSubMappingTypes() ) { assemblers[subMappingType.getSubclassId()][stateArrayPosition] = stateAssembler; updatableAttributeMutabilityPlans[subMappingType.getSubclassId()][stateArrayPosition] = updatableAttributeMutabilityPlans[subclassId][stateArrayPosition]; @@ -381,11 +372,11 @@ public EntityInitializerImpl( } } } - final BitSet emptyBitSet = new BitSet(); + final var emptyBitSet = new BitSet(); for ( int i = 0; i < subInitializers.length; i++ ) { boolean emptySubInitializers = true; if ( subInitializers[i] != null ) { - for ( Initializer initializer : subInitializers[i] ) { + for ( var initializer : subInitializers[i] ) { if ( initializer != null ) { emptySubInitializers = false; break; @@ -432,10 +423,8 @@ public EntityInitializerImpl( ? subInitializers : eagerSubInitializers; this.collectionContainingSubInitializers = collectionContainingSubInitializers; - this.lazySets = Arrays.stream( lazySets ).map( ImmutableBitSet::valueOf ).toArray( ImmutableBitSet[]::new ); - this.maybeLazySets = Arrays.stream( maybeLazySets ) - .map( ImmutableBitSet::valueOf ) - .toArray( ImmutableBitSet[]::new ); + this.lazySets = toBitSetArray( lazySets ); + this.maybeLazySets = toBitSetArray( maybeLazySets ); this.hasLazySubInitializers = hasLazySubInitializers; this.updatableAttributeMutabilityPlans = updatableAttributeMutabilityPlans; this.notFoundAction = notFoundAction; @@ -444,6 +433,12 @@ public EntityInitializerImpl( this.affectedByFilter = affectedByFilter; } + private static ImmutableBitSet[] toBitSetArray(BitSet[] lazySets) { + return Arrays.stream( lazySets ) + .map( ImmutableBitSet::valueOf ) + .toArray( ImmutableBitSet[]::new ); + } + private static boolean isPreviousRowReuse(@Nullable InitializerParent parent) { // Traverse up the parents to find out if one of our parents has row reuse enabled while ( parent != null ) { @@ -477,7 +472,7 @@ public void resolveKey(EntityInitializerData data) { @Override public @Nullable EntityKey resolveEntityKeyOnly(RowProcessingState rowProcessingState) { assert identifierAssembler != null; - final EntityInitializerData data = getData( rowProcessingState ); + final var data = getData( rowProcessingState ); resolveKey( data, true ); try { if ( data.getState() == State.MISSING ) { @@ -494,9 +489,9 @@ public void resolveKey(EntityInitializerData data) { return data.entityKey; } finally { - final Initializer initializer = identifierAssembler.getInitializer(); + final var initializer = identifierAssembler.getInitializer(); if ( hasKeyManyToOne && initializer != null ) { - final EmbeddableInitializer embeddableInitializer = initializer.asEmbeddableInitializer(); + final var embeddableInitializer = initializer.asEmbeddableInitializer(); assert embeddableInitializer != null; embeddableInitializer.resetResolvedEntityRegistrations( rowProcessingState ); } @@ -505,7 +500,7 @@ public void resolveKey(EntityInitializerData data) { @Override public void resetResolvedEntityRegistrations(RowProcessingState rowProcessingState) { - final EntityInitializerData data = getData( rowProcessingState ); + final var data = getData( rowProcessingState ); if ( data.getState() == State.RESOLVED ) { rowProcessingState.getSession() .getPersistenceContextInternal() @@ -524,110 +519,115 @@ protected void resolveKey(EntityInitializerData data, boolean entityKeyOnly) { // todo (6.0) : atm we do not handle sequential selects // - see AbstractEntityPersister#hasSequentialSelect and // AbstractEntityPersister#getSequentialSelect in 5.2 - if ( data.getState() != State.UNINITIALIZED ) { - return; - } - data.setState( State.KEY_RESOLVED ); - - final EntityKey oldEntityKey = data.entityKey; - final Object oldEntityInstance = data.getInstance(); - final Object oldEntityInstanceForNotify = data.entityInstanceForNotify; - final EntityHolder oldEntityHolder = data.entityHolder; - // reset row state - final EntityPersister concreteDescriptor = data.concreteDescriptor = data.defaultConcreteDescriptor; - data.entityKey = null; - data.setInstance( null ); - data.entityInstanceForNotify = null; - data.entityHolder = null; + if ( data.getState() == State.UNINITIALIZED ) { + data.setState( State.KEY_RESOLVED ); + + final var oldEntityKey = data.entityKey; + final Object oldEntityInstance = data.getInstance(); + final Object oldEntityInstanceForNotify = data.entityInstanceForNotify; + final var oldEntityHolder = data.entityHolder; + // reset row state + final var concreteDescriptor = data.concreteDescriptor = data.defaultConcreteDescriptor; + data.entityKey = null; + data.setInstance( null ); + data.entityInstanceForNotify = null; + data.entityHolder = null; - final RowProcessingState rowProcessingState = data.getRowProcessingState(); - final Object id; - if ( identifierAssembler == null ) { - id = rowProcessingState.getEntityId(); - assert id != null : "Initializer requires a not null id for loading"; - } - else { - //noinspection unchecked - final Initializer initializer = - (Initializer) identifierAssembler.getInitializer(); - if ( initializer != null ) { - final InitializerData subData = initializer.getData( rowProcessingState ); - initializer.resolveKey( subData ); - if ( subData.getState() == State.MISSING ) { - setMissing( data ); - return; - } - else { - if ( concreteDescriptor == null ) { - data.concreteDescriptor = determineConcreteEntityDescriptor( - rowProcessingState, - discriminatorAssembler, - entityDescriptor - ); - assert data.concreteDescriptor != null; + final var rowProcessingState = data.getRowProcessingState(); + final Object id; + if ( identifierAssembler == null ) { + id = rowProcessingState.getEntityId(); + assert id != null : "Initializer requires a not null id for loading"; + } + else { + //noinspection unchecked + final var initializer = + (Initializer) + identifierAssembler.getInitializer(); + if ( initializer != null ) { + final var subData = initializer.getData( rowProcessingState ); + initializer.resolveKey( subData ); + if ( subData.getState() == State.MISSING ) { + setMissing( data ); + return; } - if ( hasKeyManyToOne ) { - if ( !data.shallowCached && !entityKeyOnly ) { - resolveKeySubInitializers( data ); + else { + if ( concreteDescriptor == null ) { + data.concreteDescriptor = determineConcreteEntityDescriptor( + rowProcessingState, + discriminatorAssembler, + entityDescriptor + ); + assert data.concreteDescriptor != null; + } + if ( hasKeyManyToOne ) { + if ( !data.shallowCached && !entityKeyOnly ) { + resolveKeySubInitializers( data ); + } + return; } - return; } } + id = identifierAssembler.assemble( rowProcessingState ); + if ( id == null ) { + setMissing( data ); + return; + } } - id = identifierAssembler.assemble( rowProcessingState ); - if ( id == null ) { - setMissing( data ); + + if ( oldEntityKey != null + && previousRowReuse + && oldEntityInstance != null + && areKeysEqual( oldEntityKey.getIdentifier(), id ) + && !oldEntityHolder.isDetached() ) { + data.setState( State.INITIALIZED ); + data.entityKey = oldEntityKey; + data.setInstance( oldEntityInstance ); + data.entityInstanceForNotify = oldEntityInstanceForNotify; + data.concreteDescriptor = oldEntityKey.getPersister(); + data.entityHolder = oldEntityHolder; + if ( !entityKeyOnly ) { + notifySubInitializersToReusePreviousRowInstance( data ); + } return; } - } - - if ( oldEntityKey != null && previousRowReuse && oldEntityInstance != null - && areKeysEqual( oldEntityKey.getIdentifier(), id ) && !oldEntityHolder.isDetached() ) { - data.setState( State.INITIALIZED ); - data.entityKey = oldEntityKey; - data.setInstance( oldEntityInstance ); - data.entityInstanceForNotify = oldEntityInstanceForNotify; - data.concreteDescriptor = oldEntityKey.getPersister(); - data.entityHolder = oldEntityHolder; + resolveEntityKey( data, id ); if ( !entityKeyOnly ) { - notifySubInitializersToReusePreviousRowInstance( data ); - } - return; - } - resolveEntityKey( data, id ); - if ( !entityKeyOnly ) { - // Resolve the entity instance early as we have no key many-to-one - resolveInstance( data ); - if ( !data.shallowCached ) { - if ( data.getState() == State.INITIALIZED ) { - if ( data.entityHolder.getEntityInitializer() == null ) { - // The entity is already part of the persistence context, - // so let's figure out the loaded state and only run sub-initializers if necessary - resolveInstanceSubInitializers( data ); + // Resolve the entity instance early as we have no key many-to-one + resolveInstance( data ); + if ( !data.shallowCached ) { + if ( data.getState() == State.INITIALIZED ) { + if ( data.entityHolder.getEntityInitializer() == null ) { + // The entity is already part of the persistence context, + // so let's figure out the loaded state and only run sub-initializers if necessary + resolveInstanceSubInitializers( data ); + } + // If the entity is initialized and getEntityInitializer() == this, + // we already processed a row for this entity before, + // but we still have to call resolveKeySubInitializers to activate sub-initializers, + // because a row might contain data that sub-initializers want to consume + else { + // todo: try to diff the eagerness of the sub-initializers to avoid further processing + resolveKeySubInitializers( data ); + } } - // If the entity is initialized and getEntityInitializer() == this, - // we already processed a row for this entity before, - // but we still have to call resolveKeySubInitializers to activate sub-initializers, - // because a row might contain data that sub-initializers want to consume else { - // todo: try to diff the eagerness of the sub-initializers to avoid further processing resolveKeySubInitializers( data ); } } - else { - resolveKeySubInitializers( data ); - } } } } private boolean areKeysEqual(Object key1, Object key2) { - return keyTypeForEqualsHashCode == null ? key1.equals( key2 ) : keyTypeForEqualsHashCode.isEqual( key1, key2 ); + return keyTypeForEqualsHashCode == null + ? key1.equals( key2 ) + : keyTypeForEqualsHashCode.isEqual( key1, key2 ); } protected void resolveInstanceSubInitializers(EntityInitializerData data) { final int subclassId = data.concreteDescriptor.getSubclassId(); - final EntityEntry entityEntry = data.entityHolder.getEntityEntry(); + final var entityEntry = data.entityHolder.getEntityEntry(); assert entityEntry != null : "This method should only be called if the entity is already initialized"; final Initializer[] initializers; @@ -642,15 +642,15 @@ protected void resolveInstanceSubInitializers(EntityInitializerData data) { maybeLazySet = entityEntry.getMaybeLazySet(); // Skip resolving if this initializer has no sub-initializers // or the lazy set of this initializer is a superset/contains the entity entry maybeLazySet - if ( initializers.length == 0 || maybeLazySet != null && lazySets[subclassId].contains( maybeLazySet ) ) { + if ( initializers.length == 0 + || maybeLazySet != null && lazySets[subclassId].contains( maybeLazySet ) ) { return; } } - final RowProcessingState rowProcessingState = data.getRowProcessingState(); - final PersistenceContext persistenceContext = rowProcessingState.getSession() - .getPersistenceContextInternal(); + final var rowProcessingState = data.getRowProcessingState(); + final var persistenceContext = rowProcessingState.getSession().getPersistenceContextInternal(); assert entityEntry == persistenceContext.getEntry( data.entityInstanceForNotify ); - final Object[] loadedState = entityEntry.getLoadedState(); + final var loadedState = entityEntry.getLoadedState(); final Object[] state; if ( loadedState == null ) { if ( entityEntry.getStatus() == Status.READ_ONLY ) { @@ -668,8 +668,9 @@ protected void resolveInstanceSubInitializers(EntityInitializerData data) { state = loadedState; } for ( int i = 0; i < initializers.length; i++ ) { - final Initializer initializer = initializers[i]; - if ( initializer != null && ( maybeLazySet == null || maybeLazySet.get( i ) ) ) { + final var initializer = initializers[i]; + if ( initializer != null + && ( maybeLazySet == null || maybeLazySet.get( i ) ) ) { final Object subInstance = state[i]; if ( subInstance == UNFETCHED_PROPERTY ) { // Go through the normal initializer process @@ -683,7 +684,7 @@ protected void resolveInstanceSubInitializers(EntityInitializerData data) { } private void notifySubInitializersToReusePreviousRowInstance(EntityInitializerData data) { - final EntityEntry entityEntry = data.entityHolder.getEntityEntry(); + final var entityEntry = data.entityHolder.getEntityEntry(); final Initializer[] subInitializer; final ImmutableBitSet maybeLazySet; if ( data.entityHolder.getEntityInitializer() == this ) { @@ -695,20 +696,21 @@ private void notifySubInitializersToReusePreviousRowInstance(EntityInitializerDa subInitializer = subInitializersForResolveFromInitialized[data.concreteDescriptor.getSubclassId()]; maybeLazySet = entityEntry == null ? null : entityEntry.getMaybeLazySet(); } - final RowProcessingState rowProcessingState = data.getRowProcessingState(); + final var rowProcessingState = data.getRowProcessingState(); for ( int i = 0; i < subInitializer.length; i++ ) { - final Initializer initializer = subInitializer[i]; + final var initializer = subInitializer[i]; // It is vital to only resolveFromPreviousRow only for the initializers where the state is maybe lazy, // as the initialization process for the previous row also only called those initializers - if ( initializer != null && ( maybeLazySet == null || maybeLazySet.get( i ) ) ) { + if ( initializer != null + && ( maybeLazySet == null || maybeLazySet.get( i ) ) ) { initializer.resolveFromPreviousRow( rowProcessingState ); } } } protected void resolveKeySubInitializers(EntityInitializerData data) { - final RowProcessingState rowProcessingState = data.getRowProcessingState(); - for ( Initializer initializer : subInitializers[data.concreteDescriptor.getSubclassId()] ) { + final var rowProcessingState = data.getRowProcessingState(); + for ( var initializer : subInitializers[data.concreteDescriptor.getSubclassId()] ) { if ( initializer != null ) { initializer.resolveKey( rowProcessingState ); } @@ -717,13 +719,11 @@ protected void resolveKeySubInitializers(EntityInitializerData data) { @EnsuresNonNull( "data.entityKey" ) protected void resolveEntityKey(EntityInitializerData data, Object id) { - EntityPersister concreteDescriptor = data.concreteDescriptor; + var concreteDescriptor = data.concreteDescriptor; if ( concreteDescriptor == null ) { - concreteDescriptor = data.concreteDescriptor = determineConcreteEntityDescriptor( - data.getRowProcessingState(), - discriminatorAssembler, - entityDescriptor - ); + concreteDescriptor = data.concreteDescriptor = + determineConcreteEntityDescriptor( data.getRowProcessingState(), + discriminatorAssembler, entityDescriptor ); assert concreteDescriptor != null; } data.entityKey = new EntityKey( id, concreteDescriptor ); @@ -764,7 +764,7 @@ protected void setMissing(EntityInitializerData data) { @Override public void resolveFromPreviousRow(EntityInitializerData data) { if ( data.getState() == State.UNINITIALIZED ) { - final EntityKey entityKey = data.entityKey; + final var entityKey = data.entityKey; if ( entityKey == null ) { setMissing( data ); } @@ -777,11 +777,12 @@ public void resolveFromPreviousRow(EntityInitializerData data) { @Override public void initializeInstanceFromParent(Object parentInstance, EntityInitializerData data) { - final AttributeMapping attributeMapping = getInitializedPart().asAttributeMapping(); - final Object instance = attributeMapping != null - ? attributeMapping.getValue( parentInstance ) - : parentInstance; - final SharedSessionContractImplementor session = data.getRowProcessingState().getSession(); + final var attributeMapping = getInitializedPart().asAttributeMapping(); + final Object instance = + attributeMapping != null + ? attributeMapping.getValue( parentInstance ) + : parentInstance; + final var session = data.getRowProcessingState().getSession(); if ( instance == null ) { setMissing( data ); } @@ -789,10 +790,8 @@ public void initializeInstanceFromParent(Object parentInstance, EntityInitialize data.setInstance( instance ); final Object entityInstanceForNotify = data.entityInstanceForNotify = Hibernate.unproxy( instance ); data.concreteDescriptor = session.getEntityPersister( null, entityInstanceForNotify ); - resolveEntityKey( - data, - data.concreteDescriptor.getIdentifier( entityInstanceForNotify, session ) - ); + resolveEntityKey( data, + data.concreteDescriptor.getIdentifier( entityInstanceForNotify, session ) ); data.entityHolder = session.getPersistenceContextInternal().getEntityHolder( data.entityKey ); data.setState( State.INITIALIZED ); initializeSubInstancesFromParent( data ); @@ -805,7 +804,7 @@ public boolean isResultInitializer() { } private void deepCopy(EntityPersister containerDescriptor, Object[] source, Object[] target) { - final MutabilityPlan[] updatableAttributeMutabilityPlan = + final var updatableAttributeMutabilityPlan = updatableAttributeMutabilityPlans[containerDescriptor.getSubclassId()]; for ( int i = 0; i < updatableAttributeMutabilityPlan.length; i++ ) { final Object sourceValue = source[i]; @@ -849,11 +848,11 @@ public Object getTargetInstance(EntityInitializerData data) { private final ConcurrentHashMap parentEntityAttributeTypes = new ConcurrentHashMap<>(); protected Type[] getParentEntityAttributeTypes(String attributeName) { - Type[] types = parentEntityAttributeTypes.get( attributeName ); + var types = parentEntityAttributeTypes.get( attributeName ); if ( types == null ) { types = new Type[entityDescriptor.getRootEntityDescriptor().getSubclassEntityNames().size()]; initializeAttributeType( types, entityDescriptor, attributeName ); - for ( EntityMappingType subMappingType : entityDescriptor.getSubMappingTypes() ) { + for ( var subMappingType : entityDescriptor.getSubMappingTypes() ) { initializeAttributeType( types, subMappingType.getEntityPersister(), attributeName ); } parentEntityAttributeTypes.putIfAbsent( attributeName, types ); @@ -878,17 +877,16 @@ protected void initializeAttributeType(Type[] attributeTypes, EntityPersister en else { assert entityDescriptor.hasSubclasses() : "Reading a discriminator from a result set should only happen if the entity has subclasses"; - final EntityDiscriminatorMapping discriminatorMapping = entityDescriptor.getDiscriminatorMapping(); + final var discriminatorMapping = entityDescriptor.getDiscriminatorMapping(); assert discriminatorMapping != null; final Object discriminator = discriminatorAssembler.extractRawValue( rowProcessingState ); - final DiscriminatorValueDetails discriminatorDetails = - discriminatorMapping.resolveDiscriminatorValue( discriminator ); + final var discriminatorDetails = discriminatorMapping.resolveDiscriminatorValue( discriminator ); if ( discriminatorDetails == null ) { assert discriminator == null : "Discriminator details should only be null for null values"; return null; } else { - final EntityMappingType indicatedEntity = discriminatorDetails.getIndicatedEntity(); + final var indicatedEntity = discriminatorDetails.getIndicatedEntity(); if ( indicatedEntity.isTypeOrSuperType( entityDescriptor ) ) { return indicatedEntity.getEntityPersister(); } @@ -921,169 +919,174 @@ protected boolean useEmbeddedIdentifierInstanceAsEntity(EntityInitializerData da public void resolveInstance(Object instance, EntityInitializerData data) { if ( instance == null ) { setMissing( data ); - return; } - data.setInstance( instance ); - final LazyInitializer lazyInitializer = extractLazyInitializer( instance ); - final RowProcessingState rowProcessingState = data.getRowProcessingState(); - final SharedSessionContractImplementor session = rowProcessingState.getSession(); - final PersistenceContext persistenceContext = session.getPersistenceContextInternal(); - if ( lazyInitializer == null ) { - // Entity is most probably initialized - data.entityInstanceForNotify = instance; - data.concreteDescriptor = session.getEntityPersister( null, instance ); - resolveEntityKey( data, data.concreteDescriptor.getIdentifier( instance, session ) ); - data.entityHolder = persistenceContext.getEntityHolder( data.entityKey ); - if ( data.entityHolder == null ) { - // Entity was most probably removed in the same session without setting this association to null. - // Since this load request can happen through `find()` which doesn't auto-flush on association joins, - // the entity must be fully initialized, even if it is removed already - data.entityHolder = persistenceContext.claimEntityHolderIfPossible( - data.entityKey, - data.entityInstanceForNotify, - rowProcessingState.getJdbcValuesSourceProcessingState(), - this - ); + else { + data.setInstance( instance ); + final var lazyInitializer = extractLazyInitializer( instance ); + final var rowProcessingState = data.getRowProcessingState(); + final var session = rowProcessingState.getSession(); + final var persistenceContext = session.getPersistenceContextInternal(); + if ( lazyInitializer == null ) { + // Entity is most probably initialized + data.entityInstanceForNotify = instance; + data.concreteDescriptor = session.getEntityPersister( null, instance ); + resolveEntityKey( data, data.concreteDescriptor.getIdentifier( instance, session ) ); + data.entityHolder = persistenceContext.getEntityHolder( data.entityKey ); + if ( data.entityHolder == null ) { + // Entity was most probably removed in the same session without setting this association to null. + // Since this load request can happen through `find()` which doesn't auto-flush on association joins, + // the entity must be fully initialized, even if it is removed already + data.entityHolder = + persistenceContext.claimEntityHolderIfPossible( + data.entityKey, + data.entityInstanceForNotify, + rowProcessingState.getJdbcValuesSourceProcessingState(), + this + ); + } + if ( data.concreteDescriptor.getBytecodeEnhancementMetadata().isEnhancedForLazyLoading() + && isPersistentAttributeInterceptable( data.entityInstanceForNotify ) + && getAttributeInterceptor( data.entityInstanceForNotify ) + instanceof EnhancementAsProxyLazinessInterceptor enhancementInterceptor + && !enhancementInterceptor.isInitialized() ) { + data.setState( State.RESOLVED ); + } + else { + // If the entity initializer is null, we know the entity is fully initialized; + // otherwise it will be initialized by some other initializer + data.setState( data.entityHolder.getEntityInitializer() == null ? State.INITIALIZED : State.RESOLVED ); + } + + if ( data.getState() == State.RESOLVED ) { + data.entityHolder = persistenceContext.claimEntityHolderIfPossible( + data.entityKey, + data.entityInstanceForNotify, + rowProcessingState.getJdbcValuesSourceProcessingState(), + this + ); + } } - if ( data.concreteDescriptor.getBytecodeEnhancementMetadata().isEnhancedForLazyLoading() - && isPersistentAttributeInterceptable( data.entityInstanceForNotify ) - && getAttributeInterceptor( data.entityInstanceForNotify ) - instanceof EnhancementAsProxyLazinessInterceptor enhancementInterceptor - && !enhancementInterceptor.isInitialized() ) { + else if ( lazyInitializer.isUninitialized() ) { data.setState( State.RESOLVED ); - } - else { - // If the entity initializer is null, we know the entity is fully initialized, - // otherwise it will be initialized by some other initializer - data.setState( data.entityHolder.getEntityInitializer() == null ? State.INITIALIZED : State.RESOLVED ); - } - - if ( data.getState() == State.RESOLVED ) { + // Read the discriminator from the result set if necessary + data.concreteDescriptor = + discriminatorAssembler == null + ? entityDescriptor + : determineConcreteEntityDescriptor( rowProcessingState, + discriminatorAssembler, entityDescriptor ); + assert data.concreteDescriptor != null; + resolveEntityKey( data, lazyInitializer.getInternalIdentifier() ); data.entityHolder = persistenceContext.claimEntityHolderIfPossible( data.entityKey, - data.entityInstanceForNotify, + null, rowProcessingState.getJdbcValuesSourceProcessingState(), this ); + // Resolve and potentially create the entity instance + data.entityInstanceForNotify = resolveEntityInstance( data ); + lazyInitializer.setImplementation( data.entityInstanceForNotify ); + registerLoadingEntity( data, data.entityInstanceForNotify ); } - } - else if ( lazyInitializer.isUninitialized() ) { - data.setState( State.RESOLVED ); - // Read the discriminator from the result set if necessary - data.concreteDescriptor = discriminatorAssembler == null - ? entityDescriptor - : determineConcreteEntityDescriptor( rowProcessingState, discriminatorAssembler, entityDescriptor ); - assert data.concreteDescriptor != null; - resolveEntityKey( data, lazyInitializer.getInternalIdentifier() ); - data.entityHolder = persistenceContext.claimEntityHolderIfPossible( - data.entityKey, - null, - rowProcessingState.getJdbcValuesSourceProcessingState(), - this - ); - // Resolve and potentially create the entity instance - data.entityInstanceForNotify = resolveEntityInstance( data ); - lazyInitializer.setImplementation( data.entityInstanceForNotify ); - registerLoadingEntity( data, data.entityInstanceForNotify ); - } - else { - data.entityInstanceForNotify = lazyInitializer.getImplementation(); - data.concreteDescriptor = session.getEntityPersister( null, data.entityInstanceForNotify ); - resolveEntityKey( data, lazyInitializer.getInternalIdentifier() ); - data.entityHolder = persistenceContext.getEntityHolder( data.entityKey ); - // Even though the lazyInitializer reports it is initialized, check if the entity holder reports initialized, - // because in a nested initialization scenario, this nested initializer must initialize the entity - data.setState( data.entityHolder.isInitialized() ? State.INITIALIZED : State.RESOLVED ); - } - if ( identifierAssembler != null ) { - final Initializer initializer = identifierAssembler.getInitializer(); - if ( initializer != null ) { - initializer.resolveInstance( data.entityKey.getIdentifier(), rowProcessingState ); + else { + data.entityInstanceForNotify = lazyInitializer.getImplementation(); + data.concreteDescriptor = session.getEntityPersister( null, data.entityInstanceForNotify ); + resolveEntityKey( data, lazyInitializer.getInternalIdentifier() ); + data.entityHolder = persistenceContext.getEntityHolder( data.entityKey ); + // Even though the lazyInitializer reports it is initialized, check if the entity holder reports initialized, + // because in a nested initialization scenario, this nested initializer must initialize the entity + data.setState( data.entityHolder.isInitialized() ? State.INITIALIZED : State.RESOLVED ); + } + if ( identifierAssembler != null ) { + final Initializer initializer = identifierAssembler.getInitializer(); + if ( initializer != null ) { + initializer.resolveInstance( data.entityKey.getIdentifier(), rowProcessingState ); + } } - } - upgradeLockMode( data ); - if ( data.getState() == State.INITIALIZED ) { - registerReloadedEntity( data ); - resolveInstanceSubInitializers( data ); - if ( rowProcessingState.needsResolveState() ) { - // We need to read result set values to correctly populate the query cache - resolveEntityState( data ); + upgradeLockMode( data ); + if ( data.getState() == State.INITIALIZED ) { + registerReloadedEntity( data ); + resolveInstanceSubInitializers( data ); + if ( rowProcessingState.needsResolveState() ) { + // We need to read result set values to correctly populate the query cache + resolveEntityState( data ); + } + } + else { + resolveKeySubInitializers( data ); } - } - else { - resolveKeySubInitializers( data ); } } @Override public void resolveInstance(EntityInitializerData data) { - if ( data.getState() != State.KEY_RESOLVED ) { - return; - } - final RowProcessingState rowProcessingState = data.getRowProcessingState(); - data.setState( State.RESOLVED ); - if ( data.entityKey == null ) { - assert identifierAssembler != null; - final Object id = identifierAssembler.assemble( rowProcessingState ); - if ( id == null ) { - setMissing( data ); - return; + if ( data.getState() == State.KEY_RESOLVED ) { + final var rowProcessingState = data.getRowProcessingState(); + data.setState( State.RESOLVED ); + if ( data.entityKey == null ) { + assert identifierAssembler != null; + final Object id = identifierAssembler.assemble( rowProcessingState ); + if ( id == null ) { + setMissing( data ); + return; + } + resolveEntityKey( data, id ); } - resolveEntityKey( data, id ); - } - data.entityHolder = - rowProcessingState.getSession().getPersistenceContextInternal() - .claimEntityHolderIfPossible( - data.entityKey, - null, - rowProcessingState.getJdbcValuesSourceProcessingState(), - this - ); + data.entityHolder = + rowProcessingState.getSession().getPersistenceContextInternal() + .claimEntityHolderIfPossible( + data.entityKey, + null, + rowProcessingState.getJdbcValuesSourceProcessingState(), + this + ); - if ( useEmbeddedIdentifierInstanceAsEntity( data ) ) { - data.setInstance( data.entityInstanceForNotify = rowProcessingState.getEntityId() ); - } - else { - resolveEntityInstance1( data ); - if ( data.uniqueKeyAttributePath != null ) { - final SharedSessionContractImplementor session = rowProcessingState.getSession(); - final EntityPersister concreteDescriptor = getConcreteDescriptor( data ); - final EntityUniqueKey euk = new EntityUniqueKey( - concreteDescriptor.getEntityName(), - data.uniqueKeyAttributePath, - rowProcessingState.getEntityUniqueKey(), - data.uniqueKeyPropertyTypes[concreteDescriptor.getSubclassId()], - session.getFactory() - ); - session.getPersistenceContextInternal().addEntity( euk, data.getInstance() ); + if ( useEmbeddedIdentifierInstanceAsEntity( data ) ) { + data.setInstance( data.entityInstanceForNotify = rowProcessingState.getEntityId() ); } - } - - if ( data.getInstance() != null ) { - upgradeLockMode( data ); - if ( data.getState() == State.INITIALIZED ) { - registerReloadedEntity( data ); - if ( rowProcessingState.needsResolveState() ) { - // We need to read result set values to correctly populate the query cache - resolveEntityState( data ); + else { + resolveEntityInstance1( data ); + if ( data.uniqueKeyAttributePath != null ) { + final var session = rowProcessingState.getSession(); + final var concreteDescriptor = getConcreteDescriptor( data ); + final var entityUniqueKey = new EntityUniqueKey( + concreteDescriptor.getEntityName(), + data.uniqueKeyAttributePath, + rowProcessingState.getEntityUniqueKey(), + data.uniqueKeyPropertyTypes[concreteDescriptor.getSubclassId()], + session.getFactory() + ); + session.getPersistenceContextInternal().addEntity( entityUniqueKey, data.getInstance() ); } } - if ( data.shallowCached ) { - initializeSubInstancesFromParent( data ); + + if ( data.getInstance() != null ) { + upgradeLockMode( data ); + if ( data.getState() == State.INITIALIZED ) { + registerReloadedEntity( data ); + if ( rowProcessingState.needsResolveState() ) { + // We need to read result set values to correctly populate the query cache + resolveEntityState( data ); + } + } + if ( data.shallowCached ) { + initializeSubInstancesFromParent( data ); + } } } } protected void resolveEntityInstance1(EntityInitializerData data) { - final Object proxy = data.entityHolder.getProxy(); + final var entityHolder = data.entityHolder; + final Object proxy = entityHolder.getProxy(); final boolean unwrapProxy = proxy != null && referencedModelPart instanceof ToOneAttributeMapping toOneAttributeMapping && toOneAttributeMapping.isUnwrapProxy() && getConcreteDescriptor( data ).getBytecodeEnhancementMetadata().isEnhancedForLazyLoading(); - final Object entityFromExecutionContext; if ( !unwrapProxy && isProxyInstance( proxy ) ) { - if ( ( entityFromExecutionContext = getEntityFromExecutionContext( data ) ) != null ) { - data.setInstance( data.entityInstanceForNotify = entityFromExecutionContext ); + final Object entityFromExecutionContext = getEntityFromExecutionContext( data ); + if ( entityFromExecutionContext != null ) { + data.entityInstanceForNotify = entityFromExecutionContext; + data.setInstance( entityFromExecutionContext ); // If the entity comes from the execution context, it is treated as not initialized // so that we can refresh the data as requested registerReloadedEntity( data ); @@ -1095,7 +1098,7 @@ protected void resolveEntityInstance1(EntityInitializerData data) { data.entityInstanceForNotify = Hibernate.unproxy( proxy ); } else { - final LazyInitializer lazyInitializer = extractLazyInitializer( proxy ); + final var lazyInitializer = extractLazyInitializer( proxy ); assert lazyInitializer != null; data.entityInstanceForNotify = resolveEntityInstance2( data ); lazyInitializer.setImplementation( data.entityInstanceForNotify ); @@ -1103,19 +1106,19 @@ protected void resolveEntityInstance1(EntityInitializerData data) { } } else { - final Object existingEntity = data.entityHolder.getEntity(); + final Object existingEntity = entityHolder.getEntity(); if ( existingEntity != null ) { data.setInstance( data.entityInstanceForNotify = existingEntity ); - if ( data.entityHolder.getEntityInitializer() == null ) { - assert data.entityHolder.isInitialized() == isExistingEntityInitialized( existingEntity ); - if ( data.entityHolder.isInitialized() ) { + if ( entityHolder.getEntityInitializer() == null ) { + assert entityHolder.isInitialized() == isExistingEntityInitialized( existingEntity ); + if ( entityHolder.isInitialized() ) { data.setState( State.INITIALIZED ); } else if ( isResultInitializer() ) { registerLoadingEntity( data, existingEntity ); } } - else if ( data.entityHolder.getEntityInitializer() != this ) { + else if ( entityHolder.getEntityInitializer() != this ) { data.setState( State.INITIALIZED ); } else if ( data.shallowCached ) { @@ -1123,27 +1126,35 @@ else if ( data.shallowCached ) { data.setInstance( data.entityInstanceForNotify = resolveEntityInstance( data ) ); } } - else if ( ( entityFromExecutionContext = getEntityFromExecutionContext( data ) ) != null ) { - // This is the entity to refresh, so don't set the state to initialized - data.setInstance( data.entityInstanceForNotify = entityFromExecutionContext ); - if ( isResultInitializer() ) { - registerLoadingEntity( data, entityFromExecutionContext ); - } - } else { - assert data.entityHolder.getEntityInitializer() == this; - // look to see if another initializer from a parent load context or an earlier - // initializer is already loading the entity - data.setInstance( data.entityInstanceForNotify = resolveEntityInstance2( data ) ); - final Initializer idInitializer; - if ( data.entityHolder.getEntityInitializer() == this && data.getState() != State.INITIALIZED - && identifierAssembler != null - && ( idInitializer = identifierAssembler.getInitializer() ) != null ) { - // If this is the owning initializer and the returned object is not initialized, - // this means that the entity instance was just instantiated. - // In this case, we want to call "assemble" and hence "initializeInstance" on the initializer - // for possibly non-aggregated identifier mappings, so inject the virtual id representation - idInitializer.initializeInstance( data.getRowProcessingState() ); + final Object entityFromExecutionContext = getEntityFromExecutionContext( data ); + if ( entityFromExecutionContext != null ) { + // This is the entity to refresh, so don't set the state to initialized + data.entityInstanceForNotify = entityFromExecutionContext; + data.setInstance( entityFromExecutionContext ); + if ( isResultInitializer() ) { + registerLoadingEntity( data, entityFromExecutionContext ); + } + } + else { + assert entityHolder.getEntityInitializer() == this; + // look to see if another initializer from a parent load context or an earlier + // initializer is already loading the entity + final Object resolvedEntityInstance = resolveEntityInstance2( data ); + data.entityInstanceForNotify = resolvedEntityInstance; + data.setInstance( resolvedEntityInstance ); + if ( entityHolder.getEntityInitializer() == this + && data.getState() != State.INITIALIZED + && identifierAssembler != null ) { + final var idInitializer = identifierAssembler.getInitializer(); + if ( idInitializer != null ) { + // If this is the owning initializer and the returned object is not initialized, + // this means that the entity instance was just instantiated. + // In this case, we want to call "assemble" and hence "initializeInstance" on the initializer + // for possibly non-aggregated identifier mappings, so inject the virtual id representation + idInitializer.initializeInstance( data.getRowProcessingState() ); + } + } } } } @@ -1152,29 +1163,30 @@ else if ( ( entityFromExecutionContext = getEntityFromExecutionContext( data ) ) } protected Object getEntityFromExecutionContext(EntityInitializerData data) { - final RowProcessingState rowProcessingState = data.getRowProcessingState(); - final ExecutionContext executionContext = rowProcessingState.getJdbcValuesSourceProcessingState() - .getExecutionContext(); - if ( rootEntityDescriptor == executionContext.getRootEntityDescriptor() - && areKeysEqual( data.entityKey.getIdentifier(), executionContext.getEntityId() ) ) { - return executionContext.getEntityInstance(); - } - return null; + final var executionContext = + data.getRowProcessingState() + .getJdbcValuesSourceProcessingState() + .getExecutionContext(); + return rootEntityDescriptor == executionContext.getRootEntityDescriptor() + && areKeysEqual( data.entityKey.getIdentifier(), executionContext.getEntityId() ) + ? executionContext.getEntityInstance() + : null; } protected void upgradeLockMode(EntityInitializerData data) { - final RowProcessingState rowProcessingState = data.getRowProcessingState(); + final var rowProcessingState = data.getRowProcessingState(); if ( data.lockMode != LockMode.NONE && rowProcessingState.upgradeLocks() ) { - final EntityEntry entry = data.entityHolder.getEntityEntry(); - assert entry == rowProcessingState.getSession().getPersistenceContextInternal() - .getEntry( data.entityInstanceForNotify ); - if ( entry != null && entry.getLockMode().lessThan( data.lockMode ) ) { + final var entityEntry = data.entityHolder.getEntityEntry(); + assert entityEntry == + rowProcessingState.getSession().getPersistenceContextInternal() + .getEntry( data.entityInstanceForNotify ); + if ( entityEntry != null && entityEntry.getLockMode().lessThan( data.lockMode ) ) { //we only check the version when _upgrading_ lock modes - if ( versionAssembler != null && entry.getLockMode() != LockMode.NONE ) { - checkVersion( data, entry, rowProcessingState ); + if ( versionAssembler != null && entityEntry.getLockMode() != LockMode.NONE ) { + checkVersion( data, entityEntry, rowProcessingState ); } //we need to upgrade the lock mode to the mode requested - entry.setLockMode( data.lockMode ); + entityEntry.setLockMode( data.lockMode ); } } } @@ -1202,7 +1214,7 @@ private void checkVersion( // null version means the object is in the process of being loaded somewhere else in the ResultSet final Object currentVersion = versionAssembler.assemble( rowProcessingState ); if ( !data.concreteDescriptor.getVersionType().isEqual( version, currentVersion ) ) { - final StatisticsImplementor statistics = rowProcessingState.getSession().getFactory().getStatistics(); + final var statistics = rowProcessingState.getSession().getFactory().getStatistics(); if ( statistics.isStatisticsEnabled() ) { statistics.optimisticFailure( data.concreteDescriptor.getEntityName() ); } @@ -1228,7 +1240,7 @@ protected Object resolveEntityInstance2(EntityInitializerData data) { } protected Object resolveEntityInstance(EntityInitializerData data) { - final RowProcessingState rowProcessingState = data.getRowProcessingState(); + final var rowProcessingState = data.getRowProcessingState(); final Object resolved = resolveToOptionalInstance( data ); if ( resolved != null ) { registerLoadingEntity( data, resolved ); @@ -1238,12 +1250,15 @@ protected Object resolveEntityInstance(EntityInitializerData data) { if ( data.shallowCached ) { // We must load the entity this way, because the query cache entry contains only the primary key data.setState( State.INITIALIZED ); - final SharedSessionContractImplementor session = rowProcessingState.getSession(); + final var session = rowProcessingState.getSession(); assert data.entityHolder.getEntityInitializer() == this; // If this initializer owns the entity, we have to remove the entity holder, // because the subsequent loading process will claim the entity - rowProcessingState.getJdbcValuesSourceProcessingState().getLoadingEntityHolders().remove( data.entityHolder ); - session.getPersistenceContextInternal().removeEntityHolder( data.entityKey ); + rowProcessingState.getJdbcValuesSourceProcessingState() + .getLoadingEntityHolders() + .remove( data.entityHolder ); + session.getPersistenceContextInternal() + .removeEntityHolder( data.entityKey ); return session.internalLoad( data.concreteDescriptor.getEntityName(), data.entityKey.getIdentifier(), @@ -1275,8 +1290,10 @@ protected Object instantiateEntity(EntityInitializerData data) { private Object resolveToOptionalInstance(EntityInitializerData data) { if ( isResultInitializer() ) { // this isEntityReturn bit is just for entity loaders, not hql/criteria - final JdbcValuesSourceProcessingOptions processingOptions = - data.getRowProcessingState().getJdbcValuesSourceProcessingState().getProcessingOptions(); + final var processingOptions = + data.getRowProcessingState() + .getJdbcValuesSourceProcessingState() + .getProcessingOptions(); return matchesOptionalInstance( data, processingOptions ) ? processingOptions.getEffectiveOptionalObject() : null; @@ -1307,13 +1324,10 @@ private Object resolveInstanceFromCache(EntityInitializerData data) { } protected void registerLoadingEntity(EntityInitializerData data, Object instance) { - final RowProcessingState rowProcessingState = data.getRowProcessingState(); - rowProcessingState.getSession().getPersistenceContextInternal().claimEntityHolderIfPossible( - data.entityKey, - instance, - rowProcessingState.getJdbcValuesSourceProcessingState(), - this - ); + final var rowProcessingState = data.getRowProcessingState(); + final var valuesSourceProcessingState = rowProcessingState.getJdbcValuesSourceProcessingState(); + rowProcessingState.getSession().getPersistenceContextInternal() + .claimEntityHolderIfPossible( data.entityKey, instance, valuesSourceProcessingState, this ); } protected void registerReloadedEntity(EntityInitializerData data) { @@ -1335,29 +1349,31 @@ public void initializeInstance(EntityInitializerData data) { } protected boolean consistentInstance(EntityInitializerData data) { - final PersistenceContext persistenceContextInternal = - data.getRowProcessingState().getSession().getPersistenceContextInternal(); // Only call PersistenceContext#getEntity within the assert expression, as it is costly - final Object entity = persistenceContextInternal.getEntity( data.entityKey ); + final Object entity = + data.getRowProcessingState().getSession() + .getPersistenceContextInternal() + .getEntity( data.entityKey ); return entity == null || entity == data.entityInstanceForNotify; } protected void initializeEntityInstance(EntityInitializerData data) { - final RowProcessingState rowProcessingState = data.getRowProcessingState(); - final SharedSessionContractImplementor session = rowProcessingState.getSession(); - final PersistenceContext persistenceContext = session.getPersistenceContextInternal(); - final EntityKey entityKey = data.entityKey; + final var rowProcessingState = data.getRowProcessingState(); + final var session = rowProcessingState.getSession(); + final var persistenceContext = session.getPersistenceContextInternal(); + final var entityKey = data.entityKey; assert entityKey != null; final Object entityIdentifier = entityKey.getIdentifier(); - final Object[] resolvedEntityState = extractConcreteTypeStateValues( data ); + final var resolvedEntityState = extractConcreteTypeStateValues( data ); preLoad( data, resolvedEntityState ); final Object entityInstanceForNotify = data.entityInstanceForNotify; if ( isPersistentAttributeInterceptable( entityInstanceForNotify ) ) { - final PersistentAttributeInterceptor persistentAttributeInterceptor = - asPersistentAttributeInterceptable( entityInstanceForNotify ).$$_hibernate_getInterceptor(); + final var persistentAttributeInterceptor = + asPersistentAttributeInterceptable( entityInstanceForNotify ) + .$$_hibernate_getInterceptor(); if ( persistentAttributeInterceptor == null || persistentAttributeInterceptor instanceof EnhancementAsProxyLazinessInterceptor ) { // if we do this after the entity has been initialized the @@ -1376,29 +1392,20 @@ protected void initializeEntityInstance(EntityInitializerData data) { final Object version = versionAssembler != null ? versionAssembler.assemble( rowProcessingState ) : null; final Object rowId = rowIdAssembler != null ? rowIdAssembler.assemble( rowProcessingState ) : null; - // from the perspective of Hibernate, an entity is read locked as soon as it is read - // so regardless of the requested lock mode, we upgrade to at least the read level - final LockMode lockModeToAcquire; - if ( data.getRowProcessingState().isTransactionActive() ) { - lockModeToAcquire = data.lockMode == LockMode.NONE ? LockMode.READ : data.lockMode; - } - else { - // data read outside transaction is marked as unlocked - lockModeToAcquire = LockMode.NONE; - } + final var entityEntry = + persistenceContext.addEntry( + entityInstanceForNotify, + Status.LOADING, + resolvedEntityState, + rowId, + entityIdentifier, + version, + lockModeToAcquire( data ), + true, + data.concreteDescriptor, + false + ); - final EntityEntry entityEntry = persistenceContext.addEntry( - entityInstanceForNotify, - Status.LOADING, - resolvedEntityState, - rowId, - entityIdentifier, - version, - lockModeToAcquire, - true, - data.concreteDescriptor, - false - ); entityEntry.setMaybeLazySet( maybeLazySets[data.concreteDescriptor.getSubclassId()] ); data.entityHolder.setEntityEntry( entityEntry ); @@ -1411,7 +1418,7 @@ protected void initializeEntityInstance(EntityInitializerData data) { assert data.concreteDescriptor.getIdentifier( entityInstanceForNotify, session ) != null; - final StatisticsImplementor statistics = session.getFactory().getStatistics(); + final var statistics = session.getFactory().getStatistics(); if ( statistics.isStatisticsEnabled() ) { if ( !rowProcessingState.isQueryCacheHit() ) { statistics.loadEntity( data.concreteDescriptor.getEntityName() ); @@ -1426,6 +1433,18 @@ protected void initializeEntityInstance(EntityInitializerData data) { ); } + private static LockMode lockModeToAcquire(EntityInitializerData data) { + if ( data.getRowProcessingState().isTransactionActive() ) { + // from the perspective of Hibernate, an entity is read locked as soon as it is read + // so regardless of the requested lock mode, we upgrade to at least the read level + return data.lockMode == LockMode.NONE ? LockMode.READ : data.lockMode; + } + else { + // data read outside transaction is marked as unlocked + return LockMode.NONE; + } + } + protected void updateCaches( EntityInitializerData data, SharedSessionContractImplementor session, @@ -1436,7 +1455,7 @@ protected void updateCaches( // No need to put into the entity cache if this is coming from the query cache already && !data.getRowProcessingState().isQueryCacheHit() && session.getCacheMode().isPutEnabled() ) { - final EntityDataAccess cacheAccess = data.concreteDescriptor.getCacheAccessStrategy(); + final var cacheAccess = data.concreteDescriptor.getCacheAccessStrategy(); if ( cacheAccess != null ) { putInCache( data, session, persistenceContext, resolvedEntityState, version, cacheAccess ); } @@ -1480,15 +1499,12 @@ private boolean isReallyReadOnly(EntityInitializerData data, SharedSessionContra return true; } else { - final LazyInitializer lazyInitializer = extractLazyInitializer( data.getInstance() ); - if ( lazyInitializer != null ) { - // there is already a proxy for this impl - // only set the status to read-only if the proxy is read-only - return lazyInitializer.isReadOnly(); - } - else { - return isReadOnly( data.getRowProcessingState(), session ); - } + final var lazyInitializer = extractLazyInitializer( data.getInstance() ); + return lazyInitializer != null + // there is already a proxy for this impl + // only set the status to read-only if the proxy is read-only + ? lazyInitializer.isReadOnly() + : isReadOnly( data.getRowProcessingState(), session ); } } @@ -1499,20 +1515,22 @@ private void putInCache( Object[] resolvedEntityState, Object version, EntityDataAccess cacheAccess) { - final SessionFactoryImplementor factory = session.getFactory(); + final var factory = session.getFactory(); - final CacheEntry cacheEntry = data.concreteDescriptor.buildCacheEntry( - data.entityInstanceForNotify, - resolvedEntityState, - version, - session - ); - final Object cacheKey = cacheAccess.generateCacheKey( - data.entityKey.getIdentifier(), - rootEntityDescriptor, - factory, - session.getTenantIdentifier() - ); + final var cacheEntry = + data.concreteDescriptor.buildCacheEntry( + data.entityInstanceForNotify, + resolvedEntityState, + version, + session + ); + final Object cacheKey = + cacheAccess.generateCacheKey( + data.entityKey.getIdentifier(), + rootEntityDescriptor, + factory, + session.getTenantIdentifier() + ); // explicit handling of caching for rows just inserted and then somehow forced to be read // from the database *within the same transaction*. usually this is done by @@ -1520,10 +1538,10 @@ private void putInCache( // 2) Session#clear + some form of load // // we need to be careful not to clobber the lock here in the cache so that it can be rolled back if need be - final EventMonitor eventMonitor = session.getEventMonitor(); + final var eventMonitor = session.getEventMonitor(); if ( persistenceContext.wasInsertedDuringTransaction( data.concreteDescriptor, data.entityKey.getIdentifier() ) ) { boolean cacheContentChanged = false; - final DiagnosticEvent cachePutEvent = eventMonitor.beginCachePutEvent(); + final var cachePutEvent = eventMonitor.beginCachePutEvent(); try { // Updating the cache entry for entities that were inserted in this transaction // only makes sense for transactional caches. Other implementations no-op for #update @@ -1555,9 +1573,9 @@ private void putInCache( } } else { - final SessionEventListenerManager eventListenerManager = session.getEventListenerManager(); + final var eventListenerManager = session.getEventListenerManager(); boolean put = false; - final DiagnosticEvent cachePutEvent = eventMonitor.beginCachePutEvent(); + final var cachePutEvent = eventMonitor.beginCachePutEvent(); try { eventListenerManager.cachePutStart(); put = cacheAccess.putFromLoad( @@ -1578,7 +1596,7 @@ private void putInCache( put, EventMonitor.CacheActionDescription.ENTITY_LOAD ); - final StatisticsImplementor statistics = factory.getStatistics(); + final var statistics = factory.getStatistics(); if ( put && statistics.isStatisticsEnabled() ) { statistics.entityCachePut( rootEntityDescriptor.getNavigableRole(), cacheAccess.getRegion().getName() ); } @@ -1591,10 +1609,10 @@ protected void registerPossibleUniqueKeyEntries( EntityInitializerData data, Object[] resolvedEntityState, final SharedSessionContractImplementor session) { - for ( UniqueKeyEntry entry : data.concreteDescriptor.uniqueKeyEntries() ) { - final String ukName = entry.getUniqueKeyName(); - final int index = entry.getStateArrayPosition(); - final Type type = entry.getPropertyType(); + for ( var uniqueKeyEntry : data.concreteDescriptor.uniqueKeyEntries() ) { + final String uniqueKeyName = uniqueKeyEntry.getUniqueKeyName(); + final int index = uniqueKeyEntry.getStateArrayPosition(); + final Type type = uniqueKeyEntry.getPropertyType(); // polymorphism not really handled completely correctly, // perhaps...well, actually it's ok, assuming that the @@ -1613,14 +1631,15 @@ protected void registerPossibleUniqueKeyEntries( else { key = resolvedEntityState[index]; } - final EntityUniqueKey entityUniqueKey = new EntityUniqueKey( - data.concreteDescriptor.getRootEntityDescriptor().getEntityName(), - //polymorphism comment above - ukName, - key, - type, - session.getFactory() - ); + final var entityUniqueKey = + new EntityUniqueKey( + data.concreteDescriptor.getRootEntityDescriptor().getEntityName(), + //polymorphism comment above + uniqueKeyName, + key, + type, + session.getFactory() + ); session.getPersistenceContextInternal().addEntity( entityUniqueKey, data.entityInstanceForNotify ); } } @@ -1657,11 +1676,12 @@ public void resolveState(EntityInitializerData data) { if ( data.concreteDescriptor == null ) { data.concreteDescriptor = data.defaultConcreteDescriptor; if ( data.concreteDescriptor == null ) { - data.concreteDescriptor = determineConcreteEntityDescriptor( - data.getRowProcessingState(), - castNonNull( discriminatorAssembler ), - entityDescriptor - ); + data.concreteDescriptor = + determineConcreteEntityDescriptor( + data.getRowProcessingState(), + castNonNull( discriminatorAssembler ), + entityDescriptor + ); if ( data.concreteDescriptor == null ) { // this should imply the entity is missing return; @@ -1673,8 +1693,8 @@ public void resolveState(EntityInitializerData data) { protected void resolveEntityState(EntityInitializerData data) { assert data.concreteDescriptor != null; - final RowProcessingState rowProcessingState = data.getRowProcessingState(); - for ( final DomainResultAssembler assembler : assemblers[data.concreteDescriptor.getSubclassId()] ) { + final var rowProcessingState = data.getRowProcessingState(); + for ( var assembler : assemblers[data.concreteDescriptor.getSubclassId()] ) { if ( assembler != null ) { assembler.resolveState( rowProcessingState ); } @@ -1685,37 +1705,42 @@ protected boolean skipInitialization(EntityInitializerData data) { if ( data.entityHolder.getEntityInitializer() != this ) { return true; } - final RowProcessingState rowProcessingState = data.getRowProcessingState(); - final EntityEntry entry = data.entityHolder.getEntityEntry(); - assert entry == rowProcessingState.getSession().getPersistenceContextInternal().getEntry( data.entityInstanceForNotify ); - if ( entry == null ) { - return false; - } - // todo (6.0): do we really need this check ? - else if ( entry.getStatus().isDeletedOrGone() ) { - return true; - } else { - if ( isPersistentAttributeInterceptable( data.entityInstanceForNotify ) ) { - final PersistentAttributeInterceptor interceptor = - asPersistentAttributeInterceptable( data.entityInstanceForNotify ).$$_hibernate_getInterceptor(); - if ( interceptor instanceof EnhancementAsProxyLazinessInterceptor ) { - // Avoid loading the same entity proxy twice for the same result set: it could lead to errors, - // because some code writes to its input (ID in hydrated state replaced by the loaded entity, in particular). - return entry.getStatus() == Status.LOADING; - } + final var rowProcessingState = data.getRowProcessingState(); + final var entry = data.entityHolder.getEntityEntry(); + assert entry == + rowProcessingState.getSession().getPersistenceContextInternal() + .getEntry( data.entityInstanceForNotify ); + if ( entry == null ) { + return false; } + // todo (6.0): do we really need this check ? + else if ( entry.getStatus().isDeletedOrGone() ) { + return true; + } + else { + if ( isPersistentAttributeInterceptable( data.entityInstanceForNotify ) ) { + final var interceptor = + asPersistentAttributeInterceptable( data.entityInstanceForNotify ) + .$$_hibernate_getInterceptor(); + if ( interceptor instanceof EnhancementAsProxyLazinessInterceptor ) { + // Avoid loading the same entity proxy twice for the same result set: it could lead to errors, + // because some code writes to its input (ID in hydrated state replaced by the loaded entity, in particular). + return entry.getStatus() == Status.LOADING; + } + } - // If the instance to initialize is the main entity, we can't skip this. - // This can happen if we initialize an enhanced proxy. - if ( entry.getStatus() != Status.LOADING ) { // If the instance to initialize is the main entity, we can't skip this. // This can happen if we initialize an enhanced proxy. - return rowProcessingState.getJdbcValuesSourceProcessingState().getProcessingOptions() - .getEffectiveOptionalObject() != data.entityInstanceForNotify; - } - else { - return false; + if ( entry.getStatus() != Status.LOADING ) { + // If the instance to initialize is the main entity, we can't skip this. + // This can happen if we initialize an enhanced proxy. + return rowProcessingState.getJdbcValuesSourceProcessingState().getProcessingOptions() + .getEffectiveOptionalObject() != data.entityInstanceForNotify; + } + else { + return false; + } } } } @@ -1726,10 +1751,12 @@ private boolean isReadOnly(RowProcessingState rowProcessingState, SharedSessionC } protected void preLoad(EntityInitializerData data, Object[] resolvedEntityState) { - final RowProcessingState rowProcessingState = data.getRowProcessingState(); - final SharedSessionContractImplementor session = rowProcessingState.getSession(); + final var rowProcessingState = data.getRowProcessingState(); + final var session = rowProcessingState.getSession(); if ( session.isEventSource() ) { - final PreLoadEvent preLoadEvent = rowProcessingState.getJdbcValuesSourceProcessingState().getPreLoadEvent(); + final var preLoadEvent = + rowProcessingState.getJdbcValuesSourceProcessingState() + .getPreLoadEvent(); assert preLoadEvent != null; preLoadEvent.reset(); @@ -1773,8 +1800,8 @@ public EntityPersister getConcreteDescriptor(EntityInitializerData data) { protected void initializeSubInstancesFromParent(EntityInitializerData data) { if ( data.entityInstanceForNotify != null ) { - for ( Initializer initializer : subInitializers[data.concreteDescriptor.getSubclassId()] ) { - if (initializer != null) { + for ( var initializer : subInitializers[data.concreteDescriptor.getSubclassId()] ) { + if ( initializer != null ) { initializer.initializeInstanceFromParent( data.entityInstanceForNotify, data.getRowProcessingState() ); } } @@ -1783,29 +1810,29 @@ protected void initializeSubInstancesFromParent(EntityInitializerData data) { @Override protected void forEachSubInitializer(BiConsumer, RowProcessingState> consumer, InitializerData data) { - final RowProcessingState rowProcessingState = data.getRowProcessingState(); + final var rowProcessingState = data.getRowProcessingState(); if ( keyAssembler != null ) { - final Initializer initializer = keyAssembler.getInitializer(); + final var initializer = keyAssembler.getInitializer(); if ( initializer != null ) { consumer.accept( initializer, rowProcessingState ); } } if ( identifierAssembler != null ) { - final Initializer initializer = identifierAssembler.getInitializer(); + final var initializer = identifierAssembler.getInitializer(); if ( initializer != null ) { consumer.accept( initializer, rowProcessingState ); } } - final EntityInitializerData entityInitializerData = (EntityInitializerData) data; + final var entityInitializerData = (EntityInitializerData) data; if ( entityInitializerData.concreteDescriptor == null ) { - for ( Initializer initializer : allInitializers ) { + for ( var initializer : allInitializers ) { if ( initializer != null ) { consumer.accept( initializer, rowProcessingState ); } } } else { - for ( Initializer initializer : subInitializers[entityInitializerData.concreteDescriptor.getSubclassId()] ) { + for ( var initializer : subInitializers[entityInitializerData.concreteDescriptor.getSubclassId()] ) { if ( initializer != null ) { consumer.accept( initializer, rowProcessingState ); } @@ -1819,7 +1846,8 @@ public static PersistentAttributeInterceptor getAttributeInterceptor(Object enti @Override public String toString() { - return "EntityJoinedFetchInitializer(" + LoggingHelper.toLoggableString( getNavigablePath() ) + ")"; + return "EntityJoinedFetchInitializer(" + + toLoggableString( getNavigablePath() ) + ")"; } //######################### diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntitySelectFetchByUniqueKeyInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntitySelectFetchByUniqueKeyInitializer.java index 4034a824c4a9..86b70a4f92a6 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntitySelectFetchByUniqueKeyInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntitySelectFetchByUniqueKeyInitializer.java @@ -4,13 +4,7 @@ */ package org.hibernate.sql.results.graph.entity.internal; -import org.hibernate.EntityFilterException; -import org.hibernate.FetchNotFoundException; -import org.hibernate.annotations.NotFoundAction; import org.hibernate.engine.spi.EntityUniqueKey; -import org.hibernate.engine.spi.PersistenceContext; -import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.internal.log.LoggingHelper; import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.spi.NavigablePath; @@ -18,10 +12,13 @@ import org.hibernate.sql.results.graph.DomainResult; import org.hibernate.sql.results.graph.InitializerParent; +import static org.hibernate.internal.log.LoggingHelper.toLoggableString; + /** * @author Andrea Boriero */ -public class EntitySelectFetchByUniqueKeyInitializer extends EntitySelectFetchInitializer { +public class EntitySelectFetchByUniqueKeyInitializer + extends EntitySelectFetchInitializer { private final ToOneAttributeMapping fetchedAttribute; public EntitySelectFetchByUniqueKeyInitializer( @@ -41,42 +38,28 @@ protected void initialize(EntitySelectFetchInitializerData data) { final String entityName = concreteDescriptor.getEntityName(); final String uniqueKeyPropertyName = fetchedAttribute.getReferencedPropertyName(); - final SharedSessionContractImplementor session = data.getRowProcessingState().getSession(); + final var session = data.getRowProcessingState().getSession(); + final var persistenceContext = session.getPersistenceContextInternal(); - final EntityUniqueKey euk = new EntityUniqueKey( - entityName, - uniqueKeyPropertyName, - data.entityIdentifier, - concreteDescriptor.getPropertyType( uniqueKeyPropertyName ), - session.getFactory() - ); - final PersistenceContext persistenceContext = session.getPersistenceContextInternal(); - data.setInstance( persistenceContext.getEntity( euk ) ); + final var entityUniqueKey = + new EntityUniqueKey( + entityName, + uniqueKeyPropertyName, + data.entityIdentifier, + concreteDescriptor.getPropertyType( uniqueKeyPropertyName ), + session.getFactory() + ); + data.setInstance( persistenceContext.getEntity( entityUniqueKey ) ); if ( data.getInstance() == null ) { - final Object instance = concreteDescriptor.loadByUniqueKey( - uniqueKeyPropertyName, - data.entityIdentifier, - session - ); + final Object instance = + concreteDescriptor.loadByUniqueKey( uniqueKeyPropertyName, data.entityIdentifier, session ); data.setInstance( instance ); - if ( instance == null ) { - if ( toOneMapping.getNotFoundAction() != NotFoundAction.IGNORE ) { - if ( affectedByFilter ) { - throw new EntityFilterException( - entityName, - data.entityIdentifier, - toOneMapping.getNavigableRole().getFullPath() - ); - } - if ( toOneMapping.getNotFoundAction() == NotFoundAction.EXCEPTION ) { - throw new FetchNotFoundException( entityName, data.entityIdentifier ); - } - } + checkNotFound( data ); } - // If the entity was not in the Persistence Context, but was found now, - // add it to the Persistence Context - persistenceContext.addEntity( euk, instance ); + // If the entity was not in the persistence context but was found now, + // then add it to the persistence context + persistenceContext.addEntity( entityUniqueKey, instance ); } if ( data.getInstance() != null ) { data.setInstance( persistenceContext.proxyFor( data.getInstance() ) ); @@ -85,6 +68,7 @@ protected void initialize(EntitySelectFetchInitializerData data) { @Override public String toString() { - return "EntitySelectFetchByUniqueKeyInitializer(" + LoggingHelper.toLoggableString( getNavigablePath() ) + ")"; + return "EntitySelectFetchByUniqueKeyInitializer(" + + toLoggableString( getNavigablePath() ) + ")"; } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntitySelectFetchInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntitySelectFetchInitializer.java index b7fc9523439a..f714c945312f 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntitySelectFetchInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntitySelectFetchInitializer.java @@ -10,17 +10,10 @@ import org.hibernate.FetchNotFoundException; import org.hibernate.Hibernate; import org.hibernate.annotations.NotFoundAction; -import org.hibernate.engine.spi.EntityHolder; import org.hibernate.engine.spi.EntityKey; -import org.hibernate.engine.spi.PersistenceContext; -import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.internal.log.LoggingHelper; -import org.hibernate.metamodel.mapping.AttributeMapping; import org.hibernate.metamodel.mapping.ModelPart; import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping; import org.hibernate.persister.entity.EntityPersister; -import org.hibernate.proxy.HibernateProxy; -import org.hibernate.proxy.LazyInitializer; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.results.graph.AssemblerCreationState; import org.hibernate.sql.results.graph.DomainResult; @@ -34,6 +27,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; +import static org.hibernate.internal.log.LoggingHelper.toLoggableString; import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer; /** @@ -82,20 +76,15 @@ public EntitySelectFetchInitializer( this.parent = parent; this.toOneMapping = toOneMapping; this.navigablePath = fetchedNavigable; - this.isPartOfKey = Initializer.isPartOfKey( fetchedNavigable, parent ); this.concreteDescriptor = concreteDescriptor; - this.keyAssembler = keyResult.createResultAssembler( this, creationState ); - this.isEnhancedForLazyLoading = concreteDescriptor.getBytecodeEnhancementMetadata().isEnhancedForLazyLoading(); this.affectedByFilter = affectedByFilter; - final Initializer initializer = keyAssembler.getInitializer(); - if ( initializer == null ) { - this.keyIsEager = false; - this.hasLazySubInitializer = false; - } - else { - this.keyIsEager = initializer.isEager(); - this.hasLazySubInitializer = !initializer.isEager() || initializer.hasLazySubInitializers(); - } + + isPartOfKey = Initializer.isPartOfKey( fetchedNavigable, parent ); + keyAssembler = keyResult.createResultAssembler( this, creationState ); + isEnhancedForLazyLoading = concreteDescriptor.getBytecodeEnhancementMetadata().isEnhancedForLazyLoading(); + + keyIsEager = keyAssembler.isEager(); + hasLazySubInitializer = keyAssembler.hasLazySubInitializers(); } @Override @@ -124,7 +113,7 @@ public void resolveFromPreviousRow(Data data) { data.setState( State.MISSING ); } else { - final Initializer initializer = keyAssembler.getInitializer(); + final var initializer = keyAssembler.getInitializer(); if ( initializer != null ) { initializer.resolveFromPreviousRow( data.getRowProcessingState() ); } @@ -135,20 +124,19 @@ public void resolveFromPreviousRow(Data data) { @Override public void resolveInstance(Data data) { - if ( data.getState() != State.KEY_RESOLVED ) { - return; - } - - final RowProcessingState rowProcessingState = data.getRowProcessingState(); - data.entityIdentifier = keyAssembler.assemble( rowProcessingState ); - - if ( data.entityIdentifier == null ) { - data.setState( State.MISSING ); - data.setInstance( null ); - return; + if ( data.getState() == State.KEY_RESOLVED ) { + final var rowProcessingState = data.getRowProcessingState(); + final Object identifier = keyAssembler.assemble( rowProcessingState ); + data.entityIdentifier = identifier; + if ( identifier == null ) { + data.setState( State.MISSING ); + data.setInstance( null ); + } + else { + data.setState( State.INITIALIZED ); + initialize( data ); + } } - data.setState( State.INITIALIZED ); - initialize( data ); } @Override @@ -159,8 +147,8 @@ public void resolveInstance(Object instance, Data data) { data.setInstance( null ); } else { - final RowProcessingState rowProcessingState = data.getRowProcessingState(); - final LazyInitializer lazyInitializer = extractLazyInitializer( data.getInstance() ); + final var rowProcessingState = data.getRowProcessingState(); + final var lazyInitializer = extractLazyInitializer( data.getInstance() ); if ( lazyInitializer == null ) { data.setState( State.INITIALIZED ); if ( keyIsEager ) { @@ -181,7 +169,7 @@ else if ( lazyInitializer.isUninitialized() ) { } data.setInstance( instance ); if ( keyIsEager ) { - final Initializer initializer = keyAssembler.getInitializer(); + final var initializer = keyAssembler.getInitializer(); assert initializer != null; initializer.resolveInstance( data.entityIdentifier, rowProcessingState ); } @@ -194,20 +182,19 @@ else if ( rowProcessingState.needsResolveState() ) { @Override public void initializeInstance(Data data) { - if ( data.getState() != State.RESOLVED ) { - return; + if ( data.getState() == State.RESOLVED ) { + data.setState( State.INITIALIZED ); + Hibernate.initialize( data.getInstance() ); } - data.setState( State.INITIALIZED ); - Hibernate.initialize( data.getInstance() ); } protected void initialize(EntitySelectFetchInitializerData data) { - final RowProcessingState rowProcessingState = data.getRowProcessingState(); - final SharedSessionContractImplementor session = rowProcessingState.getSession(); - final EntityKey entityKey = new EntityKey( data.entityIdentifier, concreteDescriptor ); + final var rowProcessingState = data.getRowProcessingState(); + final var session = rowProcessingState.getSession(); + final var entityKey = new EntityKey( data.entityIdentifier, concreteDescriptor ); - final PersistenceContext persistenceContext = session.getPersistenceContextInternal(); - final EntityHolder holder = persistenceContext.getEntityHolder( entityKey ); + final var persistenceContext = session.getPersistenceContextInternal(); + final var holder = persistenceContext.getEntityHolder( entityKey ); if ( holder != null ) { data.setInstance( persistenceContext.proxyFor( holder, concreteDescriptor ) ); if ( holder.getEntityInitializer() == null ) { @@ -240,18 +227,7 @@ else if ( data.getInstance() == null ) { data.setInstance( instance ); if ( instance == null ) { - if ( toOneMapping.getNotFoundAction() != NotFoundAction.IGNORE ) { - if ( affectedByFilter ) { - throw new EntityFilterException( - entityName, - data.entityIdentifier, - toOneMapping.getNavigableRole().getFullPath() - ); - } - if ( toOneMapping.getNotFoundAction() == NotFoundAction.EXCEPTION ) { - throw new FetchNotFoundException( entityName, data.entityIdentifier ); - } - } + checkNotFound( data ); persistenceContext.claimEntityHolderIfPossible( new EntityKey( data.entityIdentifier, concreteDescriptor ), instance, @@ -261,18 +237,41 @@ else if ( data.getInstance() == null ) { } final boolean unwrapProxy = toOneMapping.isUnwrapProxy() && isEnhancedForLazyLoading; - final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( data.getInstance() ); + final var lazyInitializer = extractLazyInitializer( data.getInstance() ); if ( lazyInitializer != null ) { lazyInitializer.setUnwrap( unwrapProxy ); } } + void checkNotFound(EntitySelectFetchInitializerData data) { + checkNotFound( toOneMapping, affectedByFilter, + concreteDescriptor.getEntityName(), + data.entityIdentifier ); + } + + static void checkNotFound( + ToOneAttributeMapping toOneMapping, + boolean affectedByFilter, + String entityName, Object identifier) { + final var notFoundAction = toOneMapping.getNotFoundAction(); + if ( notFoundAction != NotFoundAction.IGNORE ) { + if ( affectedByFilter ) { + throw new EntityFilterException( entityName, identifier, + toOneMapping.getNavigableRole().getFullPath() ); + } + if ( notFoundAction == NotFoundAction.EXCEPTION ) { + throw new FetchNotFoundException( entityName, identifier ); + } + } + } + @Override public void initializeInstanceFromParent(Object parentInstance, Data data) { - final AttributeMapping attributeMapping = getInitializedPart().asAttributeMapping(); - final Object instance = attributeMapping != null - ? attributeMapping.getValue( parentInstance ) - : parentInstance; + final var attributeMapping = getInitializedPart().asAttributeMapping(); + final Object instance = + attributeMapping != null + ? attributeMapping.getValue( parentInstance ) + : parentInstance; if ( instance == null ) { data.setState( State.MISSING ); data.entityIdentifier = null; @@ -289,7 +288,7 @@ public void initializeInstanceFromParent(Object parentInstance, Data data) { @Override protected void forEachSubInitializer(BiConsumer, RowProcessingState> consumer, InitializerData data) { - final Initializer initializer = keyAssembler.getInitializer(); + final var initializer = keyAssembler.getInitializer(); if ( initializer != null ) { consumer.accept( initializer, data.getRowProcessingState() ); } @@ -337,7 +336,8 @@ public boolean isResultInitializer() { @Override public String toString() { - return "EntitySelectFetchInitializer(" + LoggingHelper.toLoggableString( getNavigablePath() ) + ")"; + return "EntitySelectFetchInitializer(" + + toLoggableString( getNavigablePath() ) + ")"; } public DomainResultAssembler getKeyAssembler() { diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/internal/AbstractInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/internal/AbstractInitializer.java index 8692e87010b0..131f7e1c9182 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/internal/AbstractInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/internal/AbstractInitializer.java @@ -21,7 +21,7 @@ protected AbstractInitializer(AssemblerCreationState creationState) { @Override public void startLoading(RowProcessingState rowProcessingState) { - final InitializerData data = createInitializerData( rowProcessingState ); + final var data = createInitializerData( rowProcessingState ); rowProcessingState.setInitializerData( initializerId, data ); forEachSubInitializer( Initializer::startLoading, data ); } @@ -52,5 +52,4 @@ public void finishUpRow(Data data) { protected abstract void forEachSubInitializer( BiConsumer, RowProcessingState> consumer, InitializerData data); - }