Skip to content

Commit 9cd6d29

Browse files
committed
[#2806] Upgrade Hibernate ORM to 7.1.9.Final
Requires some changes to the initializers because of [HHH-19910](https://hibernate.atlassian.net/browse/HHH-19910) and [HHH-19805](https://hibernate.atlassian.net/browse/HHH-19805). Because of a regression in ORM, I disabled `FetchModeSubselectEagerTest#testEagerFetchQuery` See ORM issue: [HHH-19949](https://hibernate.atlassian.net/browse/HHH-19949).
1 parent 271cb69 commit 9cd6d29

File tree

5 files changed

+151
-120
lines changed

5 files changed

+151
-120
lines changed

gradle/libs.versions.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[versions]
22
assertjVersion = "3.27.6"
3-
hibernateOrmVersion = "7.1.8.Final"
4-
hibernateOrmGradlePluginVersion = "7.1.8.Final"
3+
hibernateOrmVersion = "7.1.9.Final"
4+
hibernateOrmGradlePluginVersion = "7.1.9.Final"
55
jacksonDatabindVersion = "2.20.1"
66
jbossLoggingAnnotationVersion = "3.0.4.Final"
77
jbossLoggingVersion = "3.6.1.Final"

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

Lines changed: 104 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -100,109 +100,124 @@ public CompletionStage<Void> reactiveResolveInstance(EntityDelayedFetchInitializ
100100
final RowProcessingState rowProcessingState = data.getRowProcessingState();
101101
data.setEntityIdentifier( getIdentifierAssembler().assemble( rowProcessingState ) );
102102

103-
CompletionStage<Void> stage = voidFuture();
104103
if ( data.getEntityIdentifier() == null ) {
105104
data.setInstance( null );
106105
data.setState( State.MISSING );
106+
return voidFuture();
107107
}
108-
else {
109-
final SharedSessionContractImplementor session = rowProcessingState.getSession();
110-
111-
final EntityPersister entityPersister = referencedModelPart.getEntityMappingType().getEntityPersister();
112-
final EntityPersister concreteDescriptor;
113-
if ( getDiscriminatorAssembler() != null ) {
114-
concreteDescriptor = determineConcreteEntityDescriptor( rowProcessingState, getDiscriminatorAssembler(), entityPersister );
115-
if ( concreteDescriptor == null ) {
116-
// If we find no discriminator it means there's no entity in the target table
117-
if ( !referencedModelPart.isOptional() ) {
118-
throw new FetchNotFoundException( entityPersister.getEntityName(), data.getEntityIdentifier() );
119-
}
120-
data.setInstance( null );
121-
data.setState( State.MISSING );
122-
return voidFuture();
123-
}
124-
}
125-
else {
126-
concreteDescriptor = entityPersister;
127-
}
128108

129-
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
130-
if ( isSelectByUniqueKey() ) {
131-
final String uniqueKeyPropertyName = referencedModelPart.getReferencedPropertyName();
132-
final Type uniqueKeyPropertyType = uniqueKeyPropertyName == null
133-
? concreteDescriptor.getIdentifierType()
134-
: session.getFactory().getRuntimeMetamodels().getReferencedPropertyType( concreteDescriptor.getEntityName(), uniqueKeyPropertyName );
135-
final EntityUniqueKey euk = new EntityUniqueKey(
136-
concreteDescriptor.getEntityName(),
137-
uniqueKeyPropertyName,
138-
data.getEntityIdentifier(),
139-
uniqueKeyPropertyType,
140-
session.getFactory()
141-
);
142-
data.setInstance( persistenceContext.getEntity( euk ) );
143-
if ( data.getInstance() == null ) {
144-
// For unique-key mappings, we always use bytecode-laziness if possible,
145-
// because we can't generate a proxy based on the unique key yet
146-
if ( referencedModelPart.isLazy() ) {
147-
data.setInstance( LazyPropertyInitializer.UNFETCHED_PROPERTY );
148-
}
149-
else {
150-
stage = stage
151-
.thenCompose( v -> ( (ReactiveEntityPersister) concreteDescriptor )
152-
.reactiveLoadByUniqueKey(
153-
uniqueKeyPropertyName,
154-
data.getEntityIdentifier(),
155-
session
156-
) )
157-
.thenAccept( data::setInstance )
158-
.thenAccept( v -> {
159-
// If the entity was not in the Persistence Context, but was found now,
160-
// add it to the Persistence Context
161-
if ( data.getInstance() != null ) {
162-
persistenceContext.addEntity( euk, data.getInstance() );
163-
}
164-
} );
165-
}
109+
final EntityPersister entityPersister = referencedModelPart.getEntityMappingType().getEntityPersister();
110+
final EntityPersister concreteDescriptor;
111+
if ( getDiscriminatorAssembler() != null ) {
112+
concreteDescriptor = determineConcreteEntityDescriptor(
113+
rowProcessingState,
114+
getDiscriminatorAssembler(),
115+
entityPersister
116+
);
117+
if ( concreteDescriptor == null ) {
118+
// If we find no discriminator it means there's no entity in the target table
119+
if ( !referencedModelPart.isOptional() ) {
120+
throw new FetchNotFoundException( entityPersister.getEntityName(), data.getEntityIdentifier() );
166121
}
167-
stage = stage.thenAccept( v -> {
168-
if ( data.getInstance() != null ) {
169-
data.setInstance( persistenceContext.proxyFor( data.getInstance() ) );
170-
}
171-
} );
122+
data.setInstance( null );
123+
data.setState( State.MISSING );
124+
return voidFuture();
172125
}
173-
else {
174-
final EntityKey entityKey = new EntityKey( data.getEntityIdentifier(), concreteDescriptor );
175-
final EntityHolder holder = persistenceContext.getEntityHolder( entityKey );
176-
if ( holder != null && holder.getEntity() != null ) {
177-
data.setInstance( persistenceContext.proxyFor( holder, concreteDescriptor ) );
178-
}
179-
// For primary key based mappings we only use bytecode-laziness if the attribute is optional,
180-
// because the non-optionality implies that it is safe to have a proxy
181-
else if ( referencedModelPart.isOptional() && referencedModelPart.isLazy() ) {
126+
}
127+
else {
128+
concreteDescriptor = entityPersister;
129+
}
130+
131+
return initialize( data, null, concreteDescriptor );
132+
}
133+
134+
private CompletionStage<Void> initialize(
135+
ReactiveEntityDelayedFetchInitializerData data,
136+
EntityKey entityKey,
137+
EntityPersister concreteDescriptor) {
138+
final RowProcessingState rowProcessingState = data.getRowProcessingState();
139+
final SharedSessionContractImplementor session = rowProcessingState.getSession();
140+
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
141+
if ( isSelectByUniqueKey() ) {
142+
final String uniqueKeyPropertyName = referencedModelPart.getReferencedPropertyName();
143+
final Type uniqueKeyPropertyType = uniqueKeyPropertyName == null
144+
? concreteDescriptor.getIdentifierType()
145+
: session.getFactory()
146+
.getRuntimeMetamodels()
147+
.getReferencedPropertyType( concreteDescriptor.getEntityName(), uniqueKeyPropertyName );
148+
final EntityUniqueKey euk = new EntityUniqueKey(
149+
concreteDescriptor.getEntityName(),
150+
uniqueKeyPropertyName,
151+
data.getEntityIdentifier(),
152+
uniqueKeyPropertyType,
153+
session.getFactory()
154+
);
155+
data.setInstance( persistenceContext.getEntity( euk ) );
156+
CompletionStage<Void> stage = voidFuture();
157+
if ( data.getInstance() == null ) {
158+
// For unique-key mappings, we always use bytecode-laziness if possible,
159+
// because we can't generate a proxy based on the unique key yet
160+
if ( referencedModelPart.isLazy() ) {
182161
data.setInstance( LazyPropertyInitializer.UNFETCHED_PROPERTY );
183162
}
184163
else {
185-
stage = stage.thenCompose( v -> ReactiveQueryExecutorLookup
186-
.extract( session )
187-
.reactiveInternalLoad(
188-
concreteDescriptor.getEntityName(),
189-
data.getEntityIdentifier(),
190-
false,
191-
false
192-
)
164+
stage = stage
165+
.thenCompose( v -> ( (ReactiveEntityPersister) concreteDescriptor )
166+
.reactiveLoadByUniqueKey(
167+
uniqueKeyPropertyName,
168+
data.getEntityIdentifier(),
169+
session
170+
) )
193171
.thenAccept( data::setInstance )
194-
);
172+
.thenAccept( v -> {
173+
// If the entity was not in the Persistence Context, but was found now,
174+
// add it to the Persistence Context
175+
if ( data.getInstance() != null ) {
176+
persistenceContext.addEntity( euk, data.getInstance() );
177+
}
178+
} );
179+
}
180+
}
181+
return stage.thenAccept( v -> {
182+
if ( data.getInstance() != null ) {
183+
data.setInstance( persistenceContext.proxyFor( data.getInstance() ) );
195184
}
196-
stage = stage
197-
.thenAccept( v -> {
198-
final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( data.getInstance() );
199-
if ( lazyInitializer != null ) {
200-
lazyInitializer.setUnwrap( referencedModelPart.isUnwrapProxy() && concreteDescriptor.isInstrumented() );
201-
}
202-
} );
185+
} );
186+
}
187+
else {
188+
CompletionStage<Void> stage = voidFuture();
189+
final EntityKey ek = entityKey == null
190+
? new EntityKey( data.getEntityIdentifier(), concreteDescriptor )
191+
: entityKey;
192+
final EntityHolder holder = persistenceContext.getEntityHolder( ek );
193+
if ( holder != null && holder.getEntity() != null ) {
194+
data.setInstance( persistenceContext.proxyFor( holder, concreteDescriptor ) );
195+
}
196+
// For primary key based mappings we only use bytecode-laziness if the attribute is optional,
197+
// because the non-optionality implies that it is safe to have a proxy
198+
else if ( referencedModelPart.isOptional() && referencedModelPart.isLazy() ) {
199+
data.setInstance( LazyPropertyInitializer.UNFETCHED_PROPERTY );
200+
}
201+
else {
202+
stage = stage.thenCompose( v -> ReactiveQueryExecutorLookup
203+
.extract( session )
204+
.reactiveInternalLoad(
205+
concreteDescriptor.getEntityName(),
206+
data.getEntityIdentifier(),
207+
false,
208+
false
209+
)
210+
.thenAccept( data::setInstance )
211+
);
203212
}
213+
return stage
214+
.thenAccept( v -> {
215+
final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( data.getInstance() );
216+
if ( lazyInitializer != null ) {
217+
lazyInitializer.setUnwrap( referencedModelPart.isUnwrapProxy() && concreteDescriptor.isInstrumented() );
218+
}
219+
} );
204220
}
205-
return stage;
206221
}
207222

208223
@Override

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

Lines changed: 32 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
import static org.hibernate.reactive.util.impl.CompletionStages.completedFuture;
5252
import static org.hibernate.reactive.util.impl.CompletionStages.falseFuture;
5353
import static org.hibernate.reactive.util.impl.CompletionStages.loop;
54+
import static org.hibernate.reactive.util.impl.CompletionStages.supplyStage;
5455
import static org.hibernate.reactive.util.impl.CompletionStages.trueFuture;
5556
import static org.hibernate.reactive.util.impl.CompletionStages.voidFuture;
5657

@@ -329,14 +330,26 @@ private void postResolveInstance(ReactiveEntityInitializerData data) {
329330

330331
@Override
331332
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 );
333+
if ( data.getState() == State.RESOLVED ) {
334+
if ( !skipInitialization( data ) ) {
335+
assert consistentInstance( data );
336+
return reactiveInitializeEntityInstance( (ReactiveEntityInitializerData) data );
337+
}
338+
else {
339+
if ( data.getRowProcessingState().needsResolveState() ) {
340+
// A sub-initializer might have taken responsibility for this entity,
341+
// but we still need to resolve the state to correctly populate a query cache
342+
resolveState( data );
343+
}
344+
final ReactiveEntityInitializerData reactiveData = (ReactiveEntityInitializerData) data;
345+
if ( getEntityDescriptor().getBytecodeEnhancementMetadata().isEnhancedForLazyLoading()
346+
&& reactiveData.getEntityHolder().getEntityInitializer() != this
347+
&& reactiveData.getEntityHolder().isInitialized() ) {
348+
updateInitializedEntityInstance( data );
349+
}
350+
}
351+
data.setState( State.INITIALIZED );
338352
}
339-
data.setState( State.INITIALIZED );
340353
return voidFuture();
341354
}
342355

@@ -348,7 +361,7 @@ protected CompletionStage<Void> reactiveInitializeEntityInstance(ReactiveEntityI
348361

349362
return reactiveExtractConcreteTypeStateValues( data )
350363
.thenAccept( resolvedEntityState -> {
351-
364+
rowProcessingState.getJdbcValuesSourceProcessingState().registerLoadingEntityHolder( data.getEntityHolder() );
352365
preLoad( data, resolvedEntityState );
353366

354367
if ( isPersistentAttributeInterceptable( data.getEntityInstanceForNotify() ) ) {
@@ -372,18 +385,14 @@ protected CompletionStage<Void> reactiveInitializeEntityInstance(ReactiveEntityI
372385
final Object version = getVersionAssembler() != null ? getVersionAssembler().assemble( rowProcessingState ) : null;
373386
final Object rowId = getRowIdAssembler() != null ? getRowIdAssembler().assemble( rowProcessingState ) : null;
374387

375-
// from the perspective of Hibernate, an entity is read locked as soon as it is read
376-
// so regardless of the requested lock mode, we upgrade to at least the read level
377-
final LockMode lockModeToAcquire = data.getLockMode() == LockMode.NONE ? LockMode.READ : data.getLockMode();
378-
379388
final EntityEntry entityEntry = persistenceContext.addEntry(
380389
data.getEntityInstanceForNotify(),
381390
Status.LOADING,
382391
resolvedEntityState,
383392
rowId,
384393
data.getEntityKey().getIdentifier(),
385394
version,
386-
lockModeToAcquire,
395+
lockModeToAcquire( data ),
387396
true,
388397
data.getConcreteDescriptor(),
389398
false
@@ -404,16 +413,15 @@ protected CompletionStage<Void> reactiveInitializeEntityInstance(ReactiveEntityI
404413
statistics.loadEntity( data.getConcreteDescriptor().getEntityName() );
405414
}
406415
}
407-
updateCaches(
408-
data,
409-
session,
410-
session.getPersistenceContextInternal(),
411-
resolvedEntityState,
412-
version
413-
);
416+
updateCaches( data, session, session.getPersistenceContextInternal(), resolvedEntityState, version );
414417
} );
415418
}
416419

420+
// Hibernate ORM has a similar method, but it checks if we are in a transaction first
421+
private static LockMode lockModeToAcquire(ReactiveEntityInitializerData data) {
422+
return data.getLockMode() == LockMode.NONE ? LockMode.READ : data.getLockMode();
423+
}
424+
417425
protected CompletionStage<Object[]> reactiveExtractConcreteTypeStateValues(ReactiveEntityInitializerData data) {
418426
final RowProcessingState rowProcessingState = data.getRowProcessingState();
419427
final Object[] values = new Object[data.getConcreteDescriptor().getNumberOfAttributeMappings()];
@@ -447,7 +455,9 @@ protected CompletionStage<Void> reactiveResolveEntityInstance1(ReactiveEntityIni
447455
else {
448456
data.setInstance( proxy );
449457
if ( Hibernate.isInitialized( data.getInstance() ) ) {
450-
data.setState( State.INITIALIZED );
458+
if ( data.getEntityHolder().isInitialized() ) {
459+
data.setState( State.INITIALIZED );
460+
}
451461
data.setEntityInstanceForNotify( Hibernate.unproxy( data.getInstance() ) );
452462
}
453463
else {
@@ -755,7 +765,6 @@ private CompletionStage<Boolean> initializeId(ReactiveEntityInitializerData data
755765
return trueFuture();
756766
}
757767
else {
758-
//noinspection unchecked
759768
final Initializer<InitializerData> initializer = (Initializer<InitializerData>) getIdentifierAssembler().getInitializer();
760769
if ( initializer != null ) {
761770
final InitializerData subData = initializer.getData( rowProcessingState );
@@ -807,8 +816,7 @@ public CompletionStage<Void> forEachReactiveSubInitializer(
807816
BiFunction<ReactiveInitializer<?>, RowProcessingState, CompletionStage<Void>> consumer,
808817
InitializerData data) {
809818
final RowProcessingState rowProcessingState = data.getRowProcessingState();
810-
return voidFuture()
811-
.thenCompose( v -> {
819+
return supplyStage( () -> {
812820
if ( getKeyAssembler() != null ) {
813821
final Initializer<?> initializer = getKeyAssembler().getInitializer();
814822
if ( initializer != null ) {

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

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -128,9 +128,15 @@ protected CompletionStage<Void> reactiveInitialize(EntitySelectFetchInitializerD
128128
final RowProcessingState rowProcessingState = data.getRowProcessingState();
129129
final SharedSessionContractImplementor session = rowProcessingState.getSession();
130130
final EntityKey entityKey = new EntityKey( data.getEntityIdentifier(), concreteDescriptor );
131-
132131
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
133-
final EntityHolder holder = persistenceContext.getEntityHolder( entityKey );
132+
return initialiaze( data, persistenceContext.getEntityHolder( entityKey ), (ReactiveQueryProducer) session, persistenceContext );
133+
}
134+
135+
private CompletionStage<Void> initialiaze(
136+
ReactiveEntitySelectFetchInitializerData data,
137+
EntityHolder holder,
138+
ReactiveQueryProducer session,
139+
PersistenceContext persistenceContext) {
134140
if ( holder != null ) {
135141
data.setInstance( persistenceContext.proxyFor( holder, concreteDescriptor ) );
136142
if ( holder.getEntityInitializer() == null ) {
@@ -154,7 +160,7 @@ else if ( data.getInstance() == null ) {
154160
data.setState( State.INITIALIZED );
155161
final String entityName = concreteDescriptor.getEntityName();
156162

157-
return ( (ReactiveQueryProducer) session ).reactiveInternalLoad(
163+
return session.reactiveInternalLoad(
158164
entityName,
159165
data.getEntityIdentifier(),
160166
true,
@@ -176,10 +182,10 @@ else if ( data.getInstance() == null ) {
176182
throw new FetchNotFoundException( entityName, data.getEntityIdentifier() );
177183
}
178184
}
179-
rowProcessingState.getSession().getPersistenceContextInternal().claimEntityHolderIfPossible(
185+
persistenceContext.claimEntityHolderIfPossible(
180186
new EntityKey( data.getEntityIdentifier(), concreteDescriptor ),
181187
null,
182-
rowProcessingState.getJdbcValuesSourceProcessingState(),
188+
data.getRowProcessingState().getJdbcValuesSourceProcessingState(),
183189
this
184190
);
185191
}

0 commit comments

Comments
 (0)