Skip to content

Commit 0d1644d

Browse files
committed
[#2404] Align code to ORM 7.1.0.CR2
1 parent 6421104 commit 0d1644d

File tree

5 files changed

+214
-67
lines changed

5 files changed

+214
-67
lines changed

hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveAbstractEntityPersister.java

Lines changed: 83 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributesMetadata;
3131
import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata;
3232
import org.hibernate.collection.spi.PersistentCollection;
33-
import org.hibernate.engine.internal.ManagedTypeHelper;
3433
import org.hibernate.engine.spi.EntityEntry;
3534
import org.hibernate.engine.spi.EntityKey;
3635
import org.hibernate.engine.spi.LoadQueryInfluencers;
@@ -69,11 +68,13 @@
6968
import org.hibernate.sql.ast.tree.select.SelectStatement;
7069
import org.hibernate.sql.exec.spi.JdbcParametersList;
7170
import org.hibernate.type.BasicType;
71+
import org.hibernate.type.Type;
7272

7373
import jakarta.persistence.metamodel.Attribute;
7474

7575
import static java.lang.invoke.MethodHandles.lookup;
7676
import static java.util.Collections.emptyMap;
77+
import static org.hibernate.engine.internal.ManagedTypeHelper.asPersistentAttributeInterceptable;
7778
import static org.hibernate.generator.EventType.INSERT;
7879
import static org.hibernate.generator.EventType.UPDATE;
7980
import static org.hibernate.internal.util.collections.CollectionHelper.setOfSize;
@@ -105,6 +106,8 @@
105106
*/
106107
public interface ReactiveAbstractEntityPersister extends ReactiveEntityPersister {
107108

109+
Log LOG = make( Log.class, lookup() );
110+
108111
/**
109112
* A self-reference of type {@code AbstractEntityPersister}.
110113
*
@@ -374,32 +377,51 @@ default CompletionStage<Object> reactiveInitializeLazyPropertiesFromDatastore(
374377
EntityEntry entry,
375378
String fieldName,
376379
SharedSessionContractImplementor session) {
380+
return isNonLazyPropertyName( fieldName )
381+
? initLazyProperty( entity, id, entry, fieldName, session )
382+
: initLazyProperties( entity, id, entry, fieldName, session );
383+
}
377384

378-
if ( !hasLazyProperties() ) {
379-
throw new AssertionFailure( "no lazy properties" );
380-
}
385+
boolean isNonLazyPropertyName(String fieldName);
381386

382-
final PersistentAttributeInterceptor interceptor = ManagedTypeHelper.asPersistentAttributeInterceptable( entity ).$$_hibernate_getInterceptor();
383-
if ( interceptor == null ) {
384-
throw new AssertionFailure( "Expecting bytecode interceptor to be non-null" );
385-
}
387+
private CompletionStage<Object> initLazyProperty(
388+
Object entity,
389+
Object id,
390+
EntityEntry entry,
391+
String fieldName,
392+
SharedSessionContractImplementor session) {
393+
// An eager property can be lazy because of an applied EntityGraph
394+
final int propertyIndex = getPropertyIndex( fieldName );
395+
final List<ModelPart> partsToSelect = List.of( getAttributeMapping( propertyIndex ) );
396+
return reactiveGetOrCreateLazyLoadPlan( fieldName, partsToSelect )
397+
.load( id, session )
398+
.thenApply( results -> {
399+
final Object result = results[0];
400+
initializeLazyProperty( entity, entry, result, propertyIndex, getPropertyTypes()[propertyIndex] );
401+
return result;
402+
} );
403+
}
404+
405+
ReactiveSingleIdArrayLoadPlan reactiveGetOrCreateLazyLoadPlan(String fieldName, List<ModelPart> partsToSelect);
386406

387-
make( Log.class, lookup() ).tracef( "Initializing lazy properties from datastore (triggered for `%s`)", fieldName );
407+
private CompletionStage<Object> initLazyProperties(
408+
Object entity,
409+
Object id,
410+
EntityEntry entry,
411+
String fieldName,
412+
SharedSessionContractImplementor session) {
388413

389-
final String fetchGroup = getEntityPersister().getBytecodeEnhancementMetadata()
390-
.getLazyAttributesMetadata()
391-
.getFetchGroupName( fieldName );
392-
final List<LazyAttributeDescriptor> fetchGroupAttributeDescriptors = getEntityPersister().getBytecodeEnhancementMetadata()
393-
.getLazyAttributesMetadata()
394-
.getFetchGroupAttributeDescriptors( fetchGroup );
414+
assert hasLazyProperties();
415+
LOG.tracef( "Initializing lazy properties from datastore (triggered for '%s')", fieldName );
395416

396-
@SuppressWarnings("deprecation")
397-
Set<String> initializedLazyAttributeNames = interceptor.getInitializedLazyAttributeNames();
417+
final var interceptor = asPersistentAttributeInterceptable( entity ).$$_hibernate_getInterceptor();
418+
assert interceptor != null : "Expecting bytecode interceptor to be non-null";
419+
final Set<String> initializedLazyAttributeNames = interceptor.getInitializedLazyAttributeNames();
420+
LOG.tracef( "Initializing lazy properties from datastore (triggered for `%s`)", fieldName );
398421

399-
// FIXME: How do I pass this to the query?
400-
Object[] arguments = PreparedStatementAdaptor.bind(
401-
statement -> getIdentifierType().nullSafeSet( statement, id, 1, session )
402-
);
422+
final var lazyAttributesMetadata = getBytecodeEnhancementMetadata().getLazyAttributesMetadata();
423+
final String fetchGroup = lazyAttributesMetadata.getFetchGroupName( fieldName );
424+
final var fetchGroupAttributeDescriptors = lazyAttributesMetadata.getFetchGroupAttributeDescriptors( fetchGroup );
403425

404426
return reactiveGetSQLLazySelectLoadPlan( fetchGroup )
405427
.load( id, session )
@@ -420,51 +442,55 @@ default CompletionStage<Object> initLazyProperty(
420442
PersistentAttributeInterceptor interceptor,
421443
List<LazyAttributeDescriptor> fetchGroupAttributeDescriptors,
422444
Set<String> initializedLazyAttributeNames,
423-
Object[] values) { // Load all the lazy properties that are in the same fetch group
424-
CompletionStage<Object> resultStage = nullFuture();
425-
int i = 0;
426-
for ( LazyAttributeDescriptor fetchGroupAttributeDescriptor : fetchGroupAttributeDescriptors ) {
427-
if ( initializedLazyAttributeNames.contains( fetchGroupAttributeDescriptor.getName() ) ) {
445+
Object[] results) { // Load all the lazy properties that are in the same fetch group
446+
CompletionStage<Object> finalResultStage = nullFuture();
447+
final int[] i = { 0 };
448+
for ( var fetchGroupAttributeDescriptor : fetchGroupAttributeDescriptors ) {
449+
final String attributeName = fetchGroupAttributeDescriptor.getName();
450+
final boolean previousInitialized = initializedLazyAttributeNames.contains( attributeName );
451+
final int index = i[0]++;
452+
if ( previousInitialized ) {
428453
// Already initialized
429-
if ( fetchGroupAttributeDescriptor.getName().equals( fieldName ) ) {
430-
resultStage = completedFuture( entry.getLoadedValue( fetchGroupAttributeDescriptor.getName() ) );
454+
if ( attributeName.equals( fieldName ) ) {
455+
finalResultStage = finalResultStage
456+
.thenApply( finalResult -> entry.getLoadedValue( fetchGroupAttributeDescriptor.getName() ) );
431457
}
458+
// it's already been initialized (e.g. by a write) so we don't want to overwrite
459+
// TODO: we should consider un-marking an attribute as dirty based on the selected value
460+
// - we know the current value:
461+
// getPropertyValue( entity, fetchGroupAttributeDescriptor.getAttributeIndex() );
462+
// - we know the selected value (see selectedValue below)
463+
// - we can use the attribute Type to tell us if they are the same
464+
// - assuming entity is a SelfDirtinessTracker we can also know if the attribute is currently
465+
// considered dirty, and if really not dirty we would do the un-marking
466+
// - of course that would mean a new method on SelfDirtinessTracker to allow un-marking
432467
continue;
433468
}
434469

435-
final Object selectedValue = values[i++];
436-
if ( selectedValue instanceof CompletionStage ) {
470+
final Object result = results[index];
471+
if ( result instanceof CompletionStage ) {
437472
// This happens with a lazy one-to-one (bytecode enhancement enabled)
438-
CompletionStage<Object> selectedValueStage = (CompletionStage<Object>) selectedValue;
439-
resultStage = resultStage
440-
.thenCompose( result -> selectedValueStage
441-
.thenApply( selected -> {
442-
final boolean set = initializeLazyProperty(
443-
fieldName,
444-
entity,
445-
entry,
446-
fetchGroupAttributeDescriptor.getLazyIndex(),
447-
selected
448-
);
449-
if ( set ) {
450-
interceptor.attributeInitialized( fetchGroupAttributeDescriptor.getName() );
451-
return selected;
452-
}
453-
return result;
454-
} )
455-
);
473+
final CompletionStage<Object> resultStage = (CompletionStage<Object>) result;
474+
finalResultStage = finalResultStage.thenCompose( finalResult -> resultStage
475+
.thenApply( value -> {
476+
if ( initializeLazyProperty( fieldName, entity, entry, fetchGroupAttributeDescriptor, result ) ) {
477+
interceptor.attributeInitialized( fetchGroupAttributeDescriptor.getName() );
478+
return value;
479+
}
480+
return finalResult;
481+
} )
482+
);
456483
}
457484
else {
458-
final boolean set = initializeLazyProperty( fieldName, entity, entry, fetchGroupAttributeDescriptor.getLazyIndex(), selectedValue );
459-
if ( set ) {
460-
resultStage = completedFuture( selectedValue );
485+
if ( initializeLazyProperty( fieldName, entity, entry, fetchGroupAttributeDescriptor, result ) ) {
461486
interceptor.attributeInitialized( fetchGroupAttributeDescriptor.getName() );
487+
finalResultStage = finalResultStage.thenApply( finalResult -> result );
462488
}
463489
}
464490
}
465491

466-
return resultStage.thenApply( result -> {
467-
make( Log.class, lookup() ).trace( "Done initializing lazy properties" );
492+
return finalResultStage.thenApply( result -> {
493+
LOG.trace( "Done initializing lazy properties" );
468494
return result;
469495
} );
470496
}
@@ -526,9 +552,11 @@ private CompletionStage<?> loadFromDatabaseOrCache(
526552
.load( identifier, entity, lockOptions, session );
527553
}
528554

529-
SingleIdEntityLoader<?> determineLoaderToUse(SharedSessionContractImplementor session, LockOptions lockOptions);
555+
boolean initializeLazyProperty(String fieldName, Object entity, EntityEntry entry, LazyAttributeDescriptor fetchGroupAttributeDescriptor, Object propValue);
530556

531-
boolean initializeLazyProperty(String fieldName, Object entity, EntityEntry entry, int lazyIndex, Object selectedValue);
557+
void initializeLazyProperty(Object entity, EntityEntry entry, Object propValue, int index, Type type);
558+
559+
SingleIdEntityLoader<?> determineLoaderToUse(SharedSessionContractImplementor session, LockOptions lockOptions);
532560

533561
Object initializeLazyProperty(String fieldName, Object entity, SharedSessionContractImplementor session);
534562

hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveAbstractPersisterDelegate.java

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import java.util.List;
1212
import java.util.Map;
1313
import java.util.concurrent.CompletionStage;
14+
import java.util.concurrent.ConcurrentHashMap;
1415
import java.util.function.Supplier;
1516

1617
import org.hibernate.FetchMode;
@@ -23,6 +24,7 @@
2324
import org.hibernate.generator.Generator;
2425
import org.hibernate.generator.values.GeneratedValues;
2526
import org.hibernate.id.IdentityGenerator;
27+
import org.hibernate.loader.ast.internal.LoaderSelectBuilder;
2628
import org.hibernate.loader.ast.spi.BatchLoaderFactory;
2729
import org.hibernate.loader.ast.spi.EntityBatchLoader;
2830
import org.hibernate.loader.ast.spi.MultiIdLoadOptions;
@@ -34,6 +36,7 @@
3436
import org.hibernate.metamodel.mapping.EntityMappingType;
3537
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
3638
import org.hibernate.metamodel.mapping.ManagedMappingType;
39+
import org.hibernate.metamodel.mapping.ModelPart;
3740
import org.hibernate.metamodel.mapping.SingularAttributeMapping;
3841
import org.hibernate.metamodel.mapping.internal.EmbeddedIdentifierMappingImpl;
3942
import org.hibernate.metamodel.mapping.internal.GeneratedValuesProcessor;
@@ -48,6 +51,7 @@
4851
import org.hibernate.query.named.NamedQueryMemento;
4952
import org.hibernate.reactive.loader.ast.internal.ReactiveMultiIdEntityLoaderArrayParam;
5053
import org.hibernate.reactive.loader.ast.internal.ReactiveMultiIdEntityLoaderStandard;
54+
import org.hibernate.reactive.loader.ast.internal.ReactiveSingleIdArrayLoadPlan;
5155
import org.hibernate.reactive.loader.ast.internal.ReactiveSingleIdEntityLoaderProvidedQueryImpl;
5256
import org.hibernate.reactive.loader.ast.internal.ReactiveSingleIdEntityLoaderStandardImpl;
5357
import org.hibernate.reactive.loader.ast.internal.ReactiveSingleUniqueKeyEntityLoaderStandard;
@@ -64,6 +68,8 @@
6468
import org.hibernate.reactive.sql.results.internal.ReactiveEntityResultImpl;
6569
import org.hibernate.spi.NavigablePath;
6670
import org.hibernate.sql.ast.tree.from.TableGroup;
71+
import org.hibernate.sql.ast.tree.select.SelectStatement;
72+
import org.hibernate.sql.exec.spi.JdbcParametersList;
6773
import org.hibernate.sql.results.graph.DomainResult;
6874
import org.hibernate.sql.results.graph.DomainResultCreationState;
6975
import org.hibernate.sql.results.graph.Fetch;
@@ -90,6 +96,7 @@ public class ReactiveAbstractPersisterDelegate {
9096
private final EntityPersister entityDescriptor;
9197

9298
private Map<SingularAttributeMapping, ReactiveSingleUniqueKeyEntityLoader<Object>> uniqueKeyLoadersNew;
99+
private ConcurrentHashMap<String, ReactiveSingleIdArrayLoadPlan> nonLazyPropertyLoadPlansByName;
93100

94101
public ReactiveAbstractPersisterDelegate(
95102
final EntityPersister entityPersister,
@@ -347,6 +354,61 @@ else if ( entityIdentifierMapping instanceof EmbeddedIdentifierMappingImpl embed
347354
}
348355
}
349356

357+
/*
358+
* Same as AbstractEntityPersister#getOrCreateLazyLoadPlan
359+
*/
360+
public ReactiveSingleIdArrayLoadPlan getOrCreateLazyLoadPlan(String fieldName, List<ModelPart> partsToSelect) {
361+
var propertyLoadPlansByName = nonLazyPropertyLoadPlansByName;
362+
if ( propertyLoadPlansByName == null ) {
363+
propertyLoadPlansByName = new ConcurrentHashMap<>();
364+
final ReactiveSingleIdArrayLoadPlan newLazyLoanPlan = createLazyLoadPlan( partsToSelect );
365+
propertyLoadPlansByName.put( fieldName, newLazyLoanPlan );
366+
nonLazyPropertyLoadPlansByName = propertyLoadPlansByName;
367+
return newLazyLoanPlan;
368+
}
369+
else {
370+
final ReactiveSingleIdArrayLoadPlan lazyLoanPlan = nonLazyPropertyLoadPlansByName.get( fieldName );
371+
if ( lazyLoanPlan == null ) {
372+
final ReactiveSingleIdArrayLoadPlan newLazyLoanPlan = createLazyLoadPlan( partsToSelect );
373+
nonLazyPropertyLoadPlansByName.put( fieldName, newLazyLoanPlan );
374+
return newLazyLoanPlan;
375+
}
376+
else {
377+
return lazyLoanPlan;
378+
}
379+
}
380+
}
381+
382+
private ReactiveSingleIdArrayLoadPlan createLazyLoadPlan(List<ModelPart> partsToSelect) {
383+
if ( partsToSelect.isEmpty() ) {
384+
// only one-to-one is lazily fetched
385+
return null;
386+
}
387+
else {
388+
final LockOptions lockOptions = new LockOptions();
389+
final JdbcParametersList.Builder jdbcParametersBuilder = JdbcParametersList.newBuilder();
390+
final SelectStatement select = LoaderSelectBuilder.createSelect(
391+
entityDescriptor,
392+
partsToSelect,
393+
entityDescriptor.getIdentifierMapping(),
394+
null,
395+
1,
396+
new LoadQueryInfluencers( entityDescriptor.getFactory() ),
397+
lockOptions,
398+
jdbcParametersBuilder::add,
399+
entityDescriptor.getFactory()
400+
);
401+
return new ReactiveSingleIdArrayLoadPlan(
402+
entityDescriptor,
403+
entityDescriptor.getIdentifierMapping(),
404+
select,
405+
jdbcParametersBuilder.build(),
406+
lockOptions,
407+
entityDescriptor.getFactory()
408+
);
409+
}
410+
}
411+
350412
private static class ReactiveNonAggregatedIdentifierMappingImpl extends NonAggregatedIdentifierMappingImpl {
351413

352414
public ReactiveNonAggregatedIdentifierMappingImpl(

hibernate-reactive-core/src/main/java/org/hibernate/reactive/persister/entity/impl/ReactiveJoinedSubclassEntityPersister.java

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import org.hibernate.HibernateException;
1313
import org.hibernate.LockMode;
1414
import org.hibernate.LockOptions;
15+
import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeDescriptor;
1516
import org.hibernate.cache.spi.access.EntityDataAccess;
1617
import org.hibernate.cache.spi.access.NaturalIdDataAccess;
1718
import org.hibernate.engine.spi.CascadeStyle;
@@ -27,6 +28,7 @@
2728
import org.hibernate.mapping.Property;
2829
import org.hibernate.metamodel.mapping.AttributeMapping;
2930
import org.hibernate.metamodel.mapping.ManagedMappingType;
31+
import org.hibernate.metamodel.mapping.ModelPart;
3032
import org.hibernate.metamodel.mapping.NaturalIdMapping;
3133
import org.hibernate.metamodel.mapping.SingularAttributeMapping;
3234
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
@@ -52,6 +54,7 @@
5254
import org.hibernate.sql.results.graph.DomainResult;
5355
import org.hibernate.sql.results.graph.DomainResultCreationState;
5456
import org.hibernate.type.EntityType;
57+
import org.hibernate.type.Type;
5558

5659
import static java.lang.invoke.MethodHandles.lookup;
5760
import static org.hibernate.reactive.logging.impl.LoggerFactory.make;
@@ -60,8 +63,7 @@
6063
* An {@link ReactiveEntityPersister} backed by {@link JoinedSubclassEntityPersister}
6164
* and {@link ReactiveAbstractEntityPersister}.
6265
*/
63-
public class ReactiveJoinedSubclassEntityPersister extends JoinedSubclassEntityPersister
64-
implements ReactiveAbstractEntityPersister {
66+
public class ReactiveJoinedSubclassEntityPersister extends JoinedSubclassEntityPersister implements ReactiveAbstractEntityPersister {
6567

6668
private static final Log LOG = make( Log.class, lookup() );
6769

@@ -76,6 +78,16 @@ public ReactiveJoinedSubclassEntityPersister(
7678
reactiveDelegate = new ReactiveAbstractPersisterDelegate( this, persistentClass, new ReactiveRuntimeModelCreationContext( creationContext ) );
7779
}
7880

81+
@Override
82+
public boolean initializeLazyProperty(String fieldName, Object entity, EntityEntry entry, LazyAttributeDescriptor fetchGroupAttributeDescriptor, Object propValue) {
83+
return super.initializeLazyProperty( fieldName, entity, entry, fetchGroupAttributeDescriptor, propValue );
84+
}
85+
86+
@Override
87+
public void initializeLazyProperty(Object entity, EntityEntry entry, Object propValue, int index, Type type) {
88+
super.initializeLazyProperty( entity, entry, propValue, index, type );
89+
}
90+
7991
@Override
8092
protected SingleIdEntityLoader<?> buildSingleIdEntityLoader() {
8193
return reactiveDelegate.buildSingleIdEntityLoader();
@@ -389,4 +401,13 @@ public ReactiveSingleIdArrayLoadPlan reactiveGetSQLLazySelectLoadPlan(String fet
389401
return this.getLazyLoadPlanByFetchGroup( getSubclassPropertyNameClosure() ).get(fetchGroup );
390402
}
391403

404+
@Override
405+
public ReactiveSingleIdArrayLoadPlan reactiveGetOrCreateLazyLoadPlan(String fieldName, List<ModelPart> partsToSelect) {
406+
return reactiveDelegate.getOrCreateLazyLoadPlan( fieldName, partsToSelect );
407+
}
408+
409+
@Override
410+
public boolean isNonLazyPropertyName(String fieldName) {
411+
return super.isNonLazyPropertyName( fieldName );
412+
}
392413
}

0 commit comments

Comments
 (0)