From df88fd15fa72b436cded5a8e68e669c0a66cdad2 Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Mon, 7 Aug 2023 10:15:53 +0200 Subject: [PATCH] HHH-17037 Changes for Hibernate Reactive Make it possible to override the SingleIdLoadPlan and the SingleIdEntityLoader. --- .../SingleIdEntityLoaderStandardImpl.java | 54 +++++++++++-------- .../AbstractCollectionPersister.java | 24 +++++++-- .../entity/AbstractEntityPersister.java | 29 +++++----- 3 files changed, 68 insertions(+), 39 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/SingleIdEntityLoaderStandardImpl.java b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/SingleIdEntityLoaderStandardImpl.java index 0e86a6ae34..cf862eb8fb 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/SingleIdEntityLoaderStandardImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/SingleIdEntityLoaderStandardImpl.java @@ -7,6 +7,7 @@ package org.hibernate.loader.ast.internal; import java.util.EnumMap; +import java.util.function.BiFunction; import org.hibernate.Internal; import org.hibernate.LockMode; @@ -29,20 +30,36 @@ public class SingleIdEntityLoaderStandardImpl extends SingleIdEntityLoaderSup private final EnumMap> selectByLockMode = new EnumMap<>( LockMode.class ); private EnumMap> selectByInternalCascadeProfile; + private final BiFunction> loadPlanCreator; + public SingleIdEntityLoaderStandardImpl( EntityMappingType entityDescriptor, SessionFactoryImplementor sessionFactory) { + this( + entityDescriptor, + sessionFactory, + (lockOptions, influencers) -> createLoadPlan( entityDescriptor, lockOptions, influencers, sessionFactory ) + ); + } + + /** + * For Hibernate Reactive. + *

+ * Hibernate Reactive needs to be able to override the LoadPlan. + *

+ */ + protected SingleIdEntityLoaderStandardImpl( + EntityMappingType entityDescriptor, + SessionFactoryImplementor sessionFactory, + BiFunction> loadPlanCreator) { // todo (6.0) : consider creating a base AST and "cloning" it super( entityDescriptor, sessionFactory ); + this.loadPlanCreator = loadPlanCreator; // see org.hibernate.persister.entity.AbstractEntityPersister#createLoaders // we should preload a few - maybe LockMode.NONE and LockMode.READ final LockOptions lockOptions = LockOptions.NONE; final LoadQueryInfluencers influencers = new LoadQueryInfluencers( sessionFactory ); - final SingleIdLoadPlan plan = createLoadPlan( - lockOptions, - influencers, - sessionFactory - ); + final SingleIdLoadPlan plan = loadPlanCreator.apply( LockOptions.NONE, influencers ); if ( isLoadPlanReusable( lockOptions, influencers ) ) { selectByLockMode.put( lockOptions.getLockMode(), plan ); } @@ -83,7 +100,7 @@ public class SingleIdEntityLoaderStandardImpl extends SingleIdEntityLoaderSup // This case is special because the filters need to be applied in order to // properly restrict the SQL/JDBC results. For this reason it has higher // precedence than even "internal" fetch profiles. - return createLoadPlan( lockOptions, loadQueryInfluencers, sessionFactory ); + return loadPlanCreator.apply( lockOptions, loadQueryInfluencers ); } else if ( loadQueryInfluencers.hasEnabledCascadingFetchProfile() && LockMode.WRITE.greaterThan( lockOptions.getLockMode() ) ) { @@ -115,17 +132,13 @@ public class SingleIdEntityLoaderStandardImpl extends SingleIdEntityLoaderSup return existing; } else { - final SingleIdLoadPlan plan = createLoadPlan( - lockOptions, - loadQueryInfluencers, - sessionFactory - ); + final SingleIdLoadPlan plan = loadPlanCreator.apply( lockOptions, loadQueryInfluencers ); selectByLockMode.put( lockOptions.getLockMode(), plan ); return plan; } } else { - return createLoadPlan( lockOptions, loadQueryInfluencers, sessionFactory ); + return loadPlanCreator.apply( lockOptions, loadQueryInfluencers ); } } @@ -148,11 +161,7 @@ public class SingleIdEntityLoaderStandardImpl extends SingleIdEntityLoaderSup } } - final SingleIdLoadPlan plan = createLoadPlan( - lockOptions, - loadQueryInfluencers, - sessionFactory - ); + final SingleIdLoadPlan plan = loadPlanCreator.apply( lockOptions, loadQueryInfluencers ); selectByInternalCascadeProfile.put( fetchProfile, plan ); return plan; } @@ -163,17 +172,18 @@ public class SingleIdEntityLoaderStandardImpl extends SingleIdEntityLoaderSup && !getLoadable().isAffectedByEnabledFetchProfiles( loadQueryInfluencers ); } - private SingleIdLoadPlan createLoadPlan( + private static SingleIdLoadPlan createLoadPlan( + EntityMappingType loadable, LockOptions lockOptions, LoadQueryInfluencers queryInfluencers, SessionFactoryImplementor sessionFactory) { final JdbcParametersList.Builder jdbcParametersBuilder = JdbcParametersList.newBuilder(); final SelectStatement sqlAst = LoaderSelectBuilder.createSelect( - getLoadable(), + loadable, // null here means to select everything null, - getLoadable().getIdentifierMapping(), + loadable.getIdentifierMapping(), null, 1, queryInfluencers, @@ -182,8 +192,8 @@ public class SingleIdEntityLoaderStandardImpl extends SingleIdEntityLoaderSup sessionFactory ); return new SingleIdLoadPlan<>( - getLoadable(), - getLoadable().getIdentifierMapping(), + loadable, + loadable.getIdentifierMapping(), sqlAst, jdbcParametersBuilder.build(), lockOptions, diff --git a/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java index 8254315336..124c78b571 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java @@ -613,10 +613,10 @@ public abstract class AbstractCollectionPersister public void postInstantiate() throws MappingException { if ( hasNamedQueryLoader() ) { // We pass null as metamodel because we did the initialization during construction already - collectionLoader = new CollectionLoaderNamedQuery( this, getNamedQueryMemento( null ) ); + collectionLoader = createNamedQueryCollectionLoader( this, getNamedQueryMemento( null ) ); } else { - collectionLoader = createCollectionLoader( new LoadQueryInfluencers( factory ) ); + collectionLoader = createNamedQueryCollectionLoader( new LoadQueryInfluencers( factory ) ); } if ( attributeMapping.getIndexDescriptor() != null ) { @@ -720,7 +720,7 @@ public abstract class AbstractCollectionPersister } return attributeMapping.isAffectedByInfluencers( influencers ) - ? createCollectionLoader( influencers ) + ? createNamedQueryCollectionLoader( influencers ) : getCollectionLoader(); } @@ -765,7 +765,7 @@ public abstract class AbstractCollectionPersister // return attributeMapping.isNotAffectedByInfluencers( loadQueryInfluencers ); // } - private CollectionLoader createCollectionLoader(LoadQueryInfluencers loadQueryInfluencers) { + private CollectionLoader createNamedQueryCollectionLoader(LoadQueryInfluencers loadQueryInfluencers) { if ( loadQueryInfluencers.effectivelyBatchLoadable( this ) ) { final int batchSize = loadQueryInfluencers.effectiveBatchSize( this ); return factory.getServiceRegistry() @@ -773,10 +773,24 @@ public abstract class AbstractCollectionPersister .createCollectionBatchLoader( batchSize, loadQueryInfluencers, attributeMapping, factory ); } else { - return new CollectionLoaderSingleKey( attributeMapping, loadQueryInfluencers, factory ); + return createSingleKeyCollectionLoader( loadQueryInfluencers ); } } + /** + * For Hibernate Reactive + */ + protected CollectionLoader createNamedQueryCollectionLoader(CollectionPersister persister, NamedQueryMemento namedQueryMemento) { + return new CollectionLoaderNamedQuery(persister, namedQueryMemento); + } + + /** + * For Hibernate Reactive + */ + protected CollectionLoader createSingleKeyCollectionLoader(LoadQueryInfluencers loadQueryInfluencers) { + return new CollectionLoaderSingleKey( attributeMapping, loadQueryInfluencers, factory ); + } + @Override public CollectionDataAccess getCacheAccessStrategy() { return cacheAccessStrategy; diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index cbd5f054ff..0d5260a81e 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -78,7 +78,6 @@ import org.hibernate.engine.internal.MutableEntityEntryFactory; import org.hibernate.engine.internal.StatefulPersistenceContext; import org.hibernate.engine.jdbc.mutation.spi.MutationExecutorService; import org.hibernate.engine.jdbc.spi.JdbcCoordinator; -import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.profile.internal.FetchProfileAffectee; import org.hibernate.engine.spi.CachedNaturalIdValueSource; import org.hibernate.engine.spi.CascadeStyle; @@ -831,7 +830,19 @@ public abstract class AbstractEntityPersister return memento; } - private SingleIdEntityLoader createSingleIdEntityLoader(LoadQueryInfluencers loadQueryInfluencers) { + /** + * For Hibernate Reactive + */ + protected SingleIdEntityLoader buildSingleIdEntityLoader() { + if ( hasNamedQueryLoader() ) { + // We must resolve the named query on-demand through the boot model because it isn't initialized yet + final NamedQueryMemento memento = getNamedQueryMemento( null ); + return new SingleIdEntityLoaderProvidedQueryImpl<>( this, memento ); + } + return buildSingleIdEntityLoader( new LoadQueryInfluencers( factory ) ); + } + + private SingleIdEntityLoader buildSingleIdEntityLoader(LoadQueryInfluencers loadQueryInfluencers) { if ( loadQueryInfluencers.effectivelyBatchLoadable( this ) ) { final int batchSize = loadQueryInfluencers.effectiveBatchSize( this ); return factory.getServiceRegistry() @@ -864,7 +875,7 @@ public abstract class AbstractEntityPersister return entityNameByTableNameMap; } - private MultiIdEntityLoader buildMultiIdLoader() { + protected MultiIdEntityLoader buildMultiIdLoader() { if ( getIdentifierType() instanceof BasicType && supportsSqlArrayType( factory.getJdbcServices().getDialect() ) ) { return new MultiIdEntityLoaderArrayParam<>( this, factory ); @@ -3588,14 +3599,8 @@ public abstract class AbstractEntityPersister @Override public final void postInstantiate() throws MappingException { doLateInit(); - if ( hasNamedQueryLoader() ) { - // We must resolve the named query on-demand through the boot model because it isn't initialized yet - final NamedQueryMemento memento = getNamedQueryMemento( null ); - singleIdLoader = new SingleIdEntityLoaderProvidedQueryImpl<>( this, memento ); - } - else { - singleIdLoader = createSingleIdEntityLoader( new LoadQueryInfluencers( factory ) ); - } + // Hibernate Reactive needs to override the loaders + singleIdLoader = buildSingleIdEntityLoader(); multiIdLoader = buildMultiIdLoader(); } @@ -3644,7 +3649,7 @@ public abstract class AbstractEntityPersister final LoadQueryInfluencers influencers = session.getLoadQueryInfluencers(); // no subselect fetching for entities for now return isAffectedByInfluencers( influencers ) - ? createSingleIdEntityLoader( influencers ) + ? buildSingleIdEntityLoader( influencers ) : getSingleIdLoader(); } }