Skip to content

Commit 45fad7c

Browse files
committed
Upgrade Hibenate ORM to 7.1.10.Final
1 parent 9d9628f commit 45fad7c

File tree

1 file changed

+127
-38
lines changed

1 file changed

+127
-38
lines changed

hibernate-reactive-core/src/main/java/org/hibernate/reactive/sql/results/graph/entity/internal/ReactiveEntityInitializerImpl.java

Lines changed: 127 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
2121
import org.hibernate.engine.spi.SharedSessionContractImplementor;
2222
import org.hibernate.engine.spi.Status;
23+
import org.hibernate.internal.util.ImmutableBitSet;
2324
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
2425
import org.hibernate.persister.entity.EntityPersister;
2526
import org.hibernate.proxy.LazyInitializer;
@@ -35,6 +36,8 @@
3536
import org.hibernate.sql.results.graph.Initializer;
3637
import org.hibernate.sql.results.graph.InitializerData;
3738
import org.hibernate.sql.results.graph.InitializerParent;
39+
import org.hibernate.sql.results.graph.UnfetchedResultAssembler;
40+
import org.hibernate.sql.results.graph.collection.internal.UnfetchedCollectionAssembler;
3841
import org.hibernate.sql.results.graph.entity.EntityResultGraphNode;
3942
import org.hibernate.sql.results.graph.entity.internal.EntityInitializerImpl;
4043
import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingOptions;
@@ -216,7 +219,7 @@ else if ( lazyInitializer.isUninitialized() ) {
216219
if ( data.getState() == State.INITIALIZED ) {
217220
registerReloadedEntity( data );
218221
resolveInstanceSubInitializers( data );
219-
if ( rowProcessingState.needsResolveState() ) {
222+
if ( data.getState() == State.INITIALIZED && rowProcessingState.needsResolveState() ) {
220223
// We need to read result set values to correctly populate the query cache
221224
resolveState( data );
222225
}
@@ -329,14 +332,28 @@ private void postResolveInstance(ReactiveEntityInitializerData data) {
329332

330333
@Override
331334
public CompletionStage<Void> reactiveInitializeInstance(EntityInitializerData data) {
332-
if ( data.getState() != State.RESOLVED ) {
333-
return voidFuture();
334-
}
335-
if ( !skipInitialization( data ) ) {
336-
assert consistentInstance( data );
337-
return reactiveInitializeEntityInstance( (ReactiveEntityInitializerData) data );
335+
final ReactiveEntityInitializerData reactiveEntityInitializerData = (ReactiveEntityInitializerData) data;
336+
if ( reactiveEntityInitializerData.getState() == State.RESOLVED ) {
337+
// todo: think about what to do when one initializer fetches a lazy basic but not the other
338+
if ( !skipInitialization( reactiveEntityInitializerData ) ) {
339+
assert consistentInstance( reactiveEntityInitializerData );
340+
return reactiveInitializeEntityInstance( reactiveEntityInitializerData )
341+
.thenAccept( unused-> reactiveEntityInitializerData.setState( State.INITIALIZED ) );
342+
}
343+
else if ( reactiveEntityInitializerData.getRowProcessingState().needsResolveState() ) {
344+
if ( reactiveEntityInitializerData.getRowProcessingState().needsResolveState() ) {
345+
// A sub-initializer might have taken responsibility for this entity,
346+
// but we still need to resolve the state to correctly populate a query cache
347+
resolveState( reactiveEntityInitializerData );
348+
}
349+
if ( getRootEntityDescriptor().getBytecodeEnhancementMetadata().isEnhancedForLazyLoading()
350+
&& reactiveEntityInitializerData.getEntityHolder().getEntityInitializer() != this
351+
&& reactiveEntityInitializerData.getEntityHolder().isInitialized() ) {
352+
updateInitializedEntityInstance( reactiveEntityInitializerData );
353+
}
354+
}
355+
reactiveEntityInitializerData.setState( State.INITIALIZED );
338356
}
339-
data.setState( State.INITIALIZED );
340357
return voidFuture();
341358
}
342359

@@ -348,6 +365,7 @@ protected CompletionStage<Void> reactiveInitializeEntityInstance(ReactiveEntityI
348365

349366
return reactiveExtractConcreteTypeStateValues( data )
350367
.thenAccept( resolvedEntityState -> {
368+
rowProcessingState.getJdbcValuesSourceProcessingState().registerLoadingEntityHolder( data.getEntityHolder() );
351369

352370
preLoad( data, resolvedEntityState );
353371

@@ -447,7 +465,9 @@ protected CompletionStage<Void> reactiveResolveEntityInstance1(ReactiveEntityIni
447465
else {
448466
data.setInstance( proxy );
449467
if ( Hibernate.isInitialized( data.getInstance() ) ) {
450-
data.setState( State.INITIALIZED );
468+
if ( data.getEntityHolder().isInitialized() ) {
469+
data.setState( State.INITIALIZED );
470+
}
451471
data.setEntityInstanceForNotify( Hibernate.unproxy( data.getInstance() ) );
452472
}
453473
else {
@@ -538,13 +558,14 @@ protected CompletionStage<Object> reactiveResolveEntityInstance(ReactiveEntityIn
538558
return completedFuture( resolved );
539559
}
540560
else {
541-
if ( rowProcessingState.isQueryCacheHit() && getEntityDescriptor().useShallowQueryCacheLayout() ) {
561+
if ( data.getShallowCached() ) {
542562
// We must load the entity this way, because the query cache entry contains only the primary key
543563
data.setState( State.INITIALIZED );
544564
final SharedSessionContractImplementor session = rowProcessingState.getSession();
545565
assert data.getEntityHolder().getEntityInitializer() == this;
546566
// If this initializer owns the entity, we have to remove the entity holder,
547567
// because the subsequent loading process will claim the entity
568+
rowProcessingState.getJdbcValuesSourceProcessingState().getLoadingEntityHolders().remove( data.getEntityHolder() );
548569
session.getPersistenceContextInternal().removeEntityHolder( data.getEntityKey() );
549570
return ( (ReactiveQueryProducer) session ).reactiveInternalLoad(
550571
data.getConcreteDescriptor().getEntityName(),
@@ -674,15 +695,39 @@ protected CompletionStage<Void> reactiveResolveKey(ReactiveEntityInitializerData
674695

675696

676697
protected CompletionStage<Void> reactiveResolveInstanceSubInitializers(ReactiveEntityInitializerData data) {
677-
final Initializer<?>[] initializers = getSubInitializers()[data.getConcreteDescriptor().getSubclassId()];
678-
if ( initializers.length == 0 ) {
679-
return voidFuture();
680-
}
698+
final int subclassId = data.getConcreteDescriptor().getSubclassId();
681699
final EntityEntry entityEntry = data.getEntityHolder().getEntityEntry();
700+
assert entityEntry != null : "This method should only be called if the entity is already initialized";
701+
702+
final Initializer<?>[] initializers;
703+
final ImmutableBitSet maybeLazySet;
704+
final boolean hasLazyInitializingSubAssemblers = hasLazyInitializingSubAssemblers();
705+
if ( data.getEntityHolder().getEntityInitializer() == this ) {
706+
// When this entity is already initialized, but this initializer runs anyway,
707+
// we only need to process collection containing initializers
708+
initializers = getCollectionContainingSubInitializers()[subclassId];
709+
maybeLazySet = null;
710+
}
711+
else {
712+
// If an entity has unfetched attributes, we should probably also invoke non-eager initializers.
713+
// Non-eager initializers only set proxies, but since that contains the FK information,
714+
// it would be wasteful not to set that information on the bytecode enhanced entity
715+
var subInitializersToUse = getRootEntityDescriptor().getBytecodeEnhancementMetadata().hasUnFetchedAttributes( data.getEntityInstanceForNotify() )
716+
? getSubInitializers()
717+
: getEagerSubInitializers();
718+
initializers = subInitializersToUse[subclassId];
719+
maybeLazySet = entityEntry.getMaybeLazySet();
720+
// Skip resolving if this initializer has no sub-initializers
721+
// or the lazy set of this initializer is a superset/contains the entity entry maybeLazySet
722+
if ( initializers.length == 0 && !hasLazyInitializingSubAssemblers
723+
|| maybeLazySet != null && getLazySets()[subclassId].contains( maybeLazySet ) ) {
724+
return voidFuture();
725+
}
726+
}
682727
final RowProcessingState rowProcessingState = data.getRowProcessingState();
683-
assert entityEntry == rowProcessingState.getSession()
684-
.getPersistenceContextInternal()
685-
.getEntry( data.getEntityInstanceForNotify() );
728+
final PersistenceContext persistenceContext = rowProcessingState.getSession()
729+
.getPersistenceContextInternal();
730+
assert entityEntry == persistenceContext.getEntry( data.getEntityInstanceForNotify() );
686731
final Object[] loadedState = entityEntry.getLoadedState();
687732
final Object[] state;
688733
if ( loadedState == null ) {
@@ -700,32 +745,76 @@ protected CompletionStage<Void> reactiveResolveInstanceSubInitializers(ReactiveE
700745
else {
701746
state = loadedState;
702747
}
703-
return loop( 0, initializers.length, i -> {
704-
final Initializer<?> initializer = initializers[i];
705-
if ( initializer != null ) {
706-
final Object subInstance = state[i];
707-
if ( subInstance == UNFETCHED_PROPERTY ) {
708-
if ( initializer instanceof ReactiveInitializer ) {
709-
return ( (ReactiveInitializer<?>) initializer )
710-
.reactiveResolveKey( rowProcessingState );
711-
}
712-
else {
713-
// Go through the normal initializer process
714-
initializer.resolveKey( rowProcessingState );
748+
if ( initializers.length == 0 ) {
749+
boolean needsLoadedValuesUpdate = false;
750+
if ( hasLazyInitializingSubAssemblers ) {
751+
var subAssemblers = getAssemblers()[subclassId];
752+
for ( int i = 0; i < state.length; i++ ) {
753+
final Object subInstance = state[i];
754+
final var assembler = subAssemblers[i];
755+
if ( subInstance == UNFETCHED_PROPERTY
756+
&& !(assembler instanceof UnfetchedResultAssembler<?> )
757+
&& !(assembler instanceof UnfetchedCollectionAssembler ) ) {
758+
// This assembler will produce a value when the underlying entity property is still lazy
759+
needsLoadedValuesUpdate = true;
760+
break;
715761
}
716762
}
717-
else {
718-
if ( initializer instanceof ReactiveInitializer ) {
719-
return ( (ReactiveInitializer<?>) initializer )
720-
.reactiveResolveInstance( subInstance, rowProcessingState );
763+
}
764+
if ( needsLoadedValuesUpdate ) {
765+
// Mark as resolved to update the state of the entity during initialization phase
766+
data.setState( State.RESOLVED );
767+
}
768+
return voidFuture();
769+
}
770+
else {
771+
final boolean[] needsLoadedValuesUpdate = new boolean[1];
772+
var eagerInitializers = getEagerSubInitializers()[subclassId];
773+
return loop( 0, initializers.length, i -> {
774+
final Initializer<?> initializer = initializers[i];
775+
if ( maybeLazySet == null || maybeLazySet.get( i ) ) {
776+
final Object subInstance = state[i];
777+
if ( initializer != null ) {
778+
if ( subInstance == UNFETCHED_PROPERTY ) {
779+
// Go through the normal initializer process
780+
if ( initializer instanceof ReactiveInitializer<?> reactiveInitializer ) {
781+
reactiveInitializer.reactiveResolveKey( rowProcessingState );
782+
}
783+
else {
784+
initializer.resolveKey( rowProcessingState );
785+
}
786+
// Assume that the initializer will produce a proxy or the real value
787+
needsLoadedValuesUpdate[0] = true;
788+
}
789+
// Avoid resolving initializers that are not lazy when the property isn't unfetched
790+
else if ( eagerInitializers.length != 0 && eagerInitializers[i] != null ) {
791+
if ( initializer instanceof ReactiveInitializer<?> reactiveInitializer ) {
792+
reactiveInitializer.reactiveResolveInstance( subInstance, rowProcessingState );
793+
}
794+
else {
795+
initializer.resolveInstance( subInstance, rowProcessingState );
796+
}
797+
}
721798
}
722-
else {
723-
initializer.resolveInstance( subInstance, rowProcessingState );
799+
else if ( !needsLoadedValuesUpdate[0] && hasLazyInitializingSubAssemblers && subInstance == UNFETCHED_PROPERTY ) {
800+
final var assembler = getAssemblers()[subclassId][i];
801+
if ( !( assembler instanceof UnfetchedResultAssembler<?> )
802+
&& !( assembler instanceof UnfetchedCollectionAssembler ) ) {
803+
// This assembler will produce a value when the underlying entity property is still lazy
804+
needsLoadedValuesUpdate[0] = true;
805+
}
724806
}
725807
}
726-
}
727-
return voidFuture();
728-
} );
808+
return voidFuture();
809+
}
810+
).thenAccept( unused ->
811+
{
812+
if ( needsLoadedValuesUpdate[0] ) {
813+
// Mark as resolved to update the state of the entity during initialization phase
814+
data.setState( State.RESOLVED );
815+
}
816+
} );
817+
}
729818
}
730819

731820
protected CompletionStage<Void> reactiveResolveKeySubInitializers(ReactiveEntityInitializerData data) {

0 commit comments

Comments
 (0)