From 94b819e70cb82c07785641bfbcb67fa96d714c35 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Fri, 18 Sep 2020 16:07:33 +0200 Subject: [PATCH] HHH-14238 Option to include collection fields in the default fetch group There is no good reason to lazily-instantiate a collection wrapper, since that operation never requires access to the database. See discussion here: https://github.com/hibernate/hibernate-reactive/issues/374 --- .../boot/internal/SessionFactoryOptionsBuilder.java | 10 ++++++++++ .../AbstractDelegatingSessionFactoryOptions.java | 5 +++++ .../hibernate/boot/spi/SessionFactoryOptions.java | 4 ++++ .../enhance/spi/interceptor/EnhancementHelper.java | 7 +++++-- .../spi/interceptor/LazyAttributesMetadata.java | 6 ++++-- .../persister/entity/AbstractEntityPersister.java | 13 +++++++++---- .../java/org/hibernate/tuple/PropertyFactory.java | 5 ++++- .../entity/BytecodeEnhancementMetadataPojoImpl.java | 5 +++-- .../org/hibernate/tuple/entity/EntityMetamodel.java | 11 ++++++++--- 9 files changed, 52 insertions(+), 14 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java index 52cf2f8ce5..e07e0e53f4 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java @@ -198,6 +198,7 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions { private boolean orderInsertsEnabled; private boolean postInsertIdentifierDelayed; private boolean enhancementAsProxyEnabled; + private boolean collectionsInDefaultFetchGroupEnabled; // JPA callbacks private boolean callbacksEnabled; @@ -1067,6 +1068,11 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions { return enhancementAsProxyEnabled; } + @Override + public boolean isCollectionsInDefaultFetchGroupEnabled() { + return collectionsInDefaultFetchGroupEnabled; + } + @Override public boolean isOmitJoinOfSuperclassTablesEnabled() { return omitJoinOfSuperclassTablesEnabled; @@ -1359,6 +1365,10 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions { mutableJpaCompliance().setCachingCompliance( enabled ); } + public void enableCollectionInDefaultFetchGroup(boolean enabled) { + this.collectionsInDefaultFetchGroupEnabled = enabled; + } + public void disableRefreshDetachedEntity() { this.allowRefreshDetachedEntity = false; } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingSessionFactoryOptions.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingSessionFactoryOptions.java index a3de3a7963..1ac730e0e5 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingSessionFactoryOptions.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingSessionFactoryOptions.java @@ -448,6 +448,11 @@ public class AbstractDelegatingSessionFactoryOptions implements SessionFactoryOp return delegate.isEnhancementAsProxyEnabled(); } + @Override + public boolean isCollectionsInDefaultFetchGroupEnabled() { + return delegate.isCollectionsInDefaultFetchGroupEnabled(); + } + @Override public boolean isOmitJoinOfSuperclassTablesEnabled() { return delegate.isOmitJoinOfSuperclassTablesEnabled(); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java index 929a33c4a2..36ddfbc4e3 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java @@ -315,5 +315,9 @@ public interface SessionFactoryOptions { return false; } + default boolean isCollectionsInDefaultFetchGroupEnabled() { + return false; + } + boolean isOmitJoinOfSuperclassTablesEnabled(); } diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/EnhancementHelper.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/EnhancementHelper.java index 89ad60a17f..261412fe7f 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/EnhancementHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/EnhancementHelper.java @@ -15,6 +15,7 @@ import org.hibernate.bytecode.BytecodeLogger; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.internal.SessionFactoryRegistry; +import org.hibernate.mapping.Collection; import org.hibernate.mapping.OneToOne; import org.hibernate.mapping.Property; import org.hibernate.mapping.ToOne; @@ -30,7 +31,8 @@ public class EnhancementHelper { public static boolean includeInBaseFetchGroup( Property bootMapping, boolean isEnhanced, - boolean allowEnhancementAsProxy) { + boolean allowEnhancementAsProxy, + boolean collectionsInDefaultFetchGroupEnabled) { final Value value = bootMapping.getValue(); if ( ! isEnhanced ) { @@ -63,7 +65,8 @@ public class EnhancementHelper { return true; } - return ! bootMapping.isLazy(); + return collectionsInDefaultFetchGroupEnabled && ( value instanceof Collection ) + || ! bootMapping.isLazy(); } public static T performWork( diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/LazyAttributesMetadata.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/LazyAttributesMetadata.java index 9da8a7c4ad..f06b78f000 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/LazyAttributesMetadata.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/LazyAttributesMetadata.java @@ -34,7 +34,8 @@ public class LazyAttributesMetadata implements Serializable { public static LazyAttributesMetadata from( PersistentClass mappedEntity, boolean isEnhanced, - boolean allowEnhancementAsProxy) { + boolean allowEnhancementAsProxy, + boolean collectionsInDefaultFetchGroupEnabled) { final Map lazyAttributeDescriptorMap = new LinkedHashMap<>(); final Map> fetchGroupToAttributesMap = new HashMap<>(); @@ -47,7 +48,8 @@ public class LazyAttributesMetadata implements Serializable { final boolean lazy = ! EnhancementHelper.includeInBaseFetchGroup( property, isEnhanced, - allowEnhancementAsProxy + allowEnhancementAsProxy, + collectionsInDefaultFetchGroupEnabled ); if ( lazy ) { final LazyAttributeDescriptor lazyAttributeDescriptor = LazyAttributeDescriptor.from( property, i, x++ ); 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 d1ba48a472..2666c922ba 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 @@ -37,6 +37,7 @@ import org.hibernate.QueryException; import org.hibernate.Session; import org.hibernate.StaleObjectStateException; import org.hibernate.StaleStateException; +import org.hibernate.boot.spi.SessionFactoryOptions; import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer; import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor; import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor; @@ -586,7 +587,9 @@ public abstract class AbstractEntityPersister this.navigableRole = new NavigableRole( persistentClass.getEntityName() ); - if ( creationContext.getSessionFactory().getSessionFactoryOptions().isSecondLevelCacheEnabled() ) { + SessionFactoryOptions sessionFactoryOptions = creationContext.getSessionFactory().getSessionFactoryOptions(); + + if ( sessionFactoryOptions.isSecondLevelCacheEnabled() ) { this.canWriteToCache = determineCanWriteToCache( persistentClass, cacheAccessStrategy ); this.canReadFromCache = determineCanReadFromCache( persistentClass, cacheAccessStrategy ); this.cacheAccessStrategy = cacheAccessStrategy; @@ -737,7 +740,8 @@ public abstract class AbstractEntityPersister final boolean lazy = ! EnhancementHelper.includeInBaseFetchGroup( prop, entityMetamodel.isInstrumented(), - creationContext.getSessionFactory().getSessionFactoryOptions().isEnhancementAsProxyEnabled() + sessionFactoryOptions.isEnhancementAsProxyEnabled(), + sessionFactoryOptions.isCollectionsInDefaultFetchGroupEnabled() ); if ( lazy ) { @@ -813,7 +817,8 @@ public abstract class AbstractEntityPersister final boolean lazy = ! EnhancementHelper.includeInBaseFetchGroup( prop, entityMetamodel.isInstrumented(), - creationContext.getSessionFactory().getSessionFactoryOptions().isEnhancementAsProxyEnabled() + sessionFactoryOptions.isEnhancementAsProxyEnabled(), + sessionFactoryOptions.isCollectionsInDefaultFetchGroupEnabled() ); while ( colIter.hasNext() ) { Selectable thing = (Selectable) colIter.next(); @@ -924,7 +929,7 @@ public abstract class AbstractEntityPersister this.cacheEntryHelper = buildCacheEntryHelper(); - if ( creationContext.getSessionFactory().getSessionFactoryOptions().isSecondLevelCacheEnabled() ) { + if ( sessionFactoryOptions.isSecondLevelCacheEnabled() ) { this.invalidateCache = canWriteToCache && determineWhetherToInvalidateCache( persistentClass, creationContext ); } else { diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/PropertyFactory.java b/hibernate-core/src/main/java/org/hibernate/tuple/PropertyFactory.java index 779c114e70..97949ebf2e 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/PropertyFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/PropertyFactory.java @@ -10,6 +10,7 @@ import java.lang.reflect.Constructor; import org.hibernate.EntityMode; import org.hibernate.HibernateException; +import org.hibernate.boot.spi.SessionFactoryOptions; import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementHelper; import org.hibernate.engine.internal.UnsavedValueFactory; import org.hibernate.engine.spi.IdentifierValue; @@ -169,10 +170,12 @@ public final class PropertyFactory { boolean alwaysDirtyCheck = type.isAssociationType() && ( (AssociationType) type ).isAlwaysDirtyChecked(); + SessionFactoryOptions sessionFactoryOptions = sessionFactory.getSessionFactoryOptions(); final boolean lazy = ! EnhancementHelper.includeInBaseFetchGroup( property, lazyAvailable, - sessionFactory.getSessionFactoryOptions().isEnhancementAsProxyEnabled() + sessionFactoryOptions.isEnhancementAsProxyEnabled(), + sessionFactoryOptions.isCollectionsInDefaultFetchGroupEnabled() ); switch ( nature ) { diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/BytecodeEnhancementMetadataPojoImpl.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/BytecodeEnhancementMetadataPojoImpl.java index de07cc6990..0e8ceeee65 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/entity/BytecodeEnhancementMetadataPojoImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/BytecodeEnhancementMetadataPojoImpl.java @@ -38,11 +38,12 @@ public final class BytecodeEnhancementMetadataPojoImpl implements BytecodeEnhanc PersistentClass persistentClass, Set identifierAttributeNames, CompositeType nonAggregatedCidMapper, - boolean allowEnhancementAsProxy) { + boolean allowEnhancementAsProxy, + boolean collectionsInDefaultFetchGroupEnabled) { final Class mappedClass = persistentClass.getMappedClass(); final boolean enhancedForLazyLoading = PersistentAttributeInterceptable.class.isAssignableFrom( mappedClass ); final LazyAttributesMetadata lazyAttributesMetadata = enhancedForLazyLoading - ? LazyAttributesMetadata.from( persistentClass, true, allowEnhancementAsProxy ) + ? LazyAttributesMetadata.from( persistentClass, true, allowEnhancementAsProxy, collectionsInDefaultFetchGroupEnabled ) : LazyAttributesMetadata.nonEnhanced( persistentClass.getEntityName() ); return new BytecodeEnhancementMetadataPojoImpl( diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java index 298cd24482..b50f0bac5c 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java @@ -19,6 +19,7 @@ import java.util.Set; import org.hibernate.EntityMode; import org.hibernate.HibernateException; import org.hibernate.MappingException; +import org.hibernate.boot.spi.SessionFactoryOptions; import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementHelper; import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata; import org.hibernate.cfg.NotYetImplementedException; @@ -140,6 +141,8 @@ public class EntityMetamodel implements Serializable { versioned = persistentClass.isVersioned(); + SessionFactoryOptions sessionFactoryOptions = sessionFactory.getSessionFactoryOptions(); + if ( persistentClass.hasPojoRepresentation() ) { final Component identifierMapperComponent = persistentClass.getIdentifierMapper(); final CompositeType nonAggregatedCidMapper; @@ -163,7 +166,8 @@ public class EntityMetamodel implements Serializable { persistentClass, idAttributeNames, nonAggregatedCidMapper, - sessionFactory.getSessionFactoryOptions().isEnhancementAsProxyEnabled() + sessionFactoryOptions.isEnhancementAsProxyEnabled(), + sessionFactoryOptions.isCollectionsInDefaultFetchGroupEnabled() ); } else { @@ -245,7 +249,8 @@ public class EntityMetamodel implements Serializable { boolean lazy = ! EnhancementHelper.includeInBaseFetchGroup( prop, bytecodeEnhancementMetadata.isEnhancedForLazyLoading(), - sessionFactory.getSessionFactoryOptions().isEnhancementAsProxyEnabled() + sessionFactoryOptions.isEnhancementAsProxyEnabled(), + sessionFactoryOptions.isCollectionsInDefaultFetchGroupEnabled() ); if ( lazy ) { @@ -407,7 +412,7 @@ public class EntityMetamodel implements Serializable { } entityMode = persistentClass.hasPojoRepresentation() ? EntityMode.POJO : EntityMode.MAP; - final EntityTuplizerFactory entityTuplizerFactory = sessionFactory.getSessionFactoryOptions().getEntityTuplizerFactory(); + final EntityTuplizerFactory entityTuplizerFactory = sessionFactoryOptions.getEntityTuplizerFactory(); final String tuplizerClassName = persistentClass.getTuplizerImplClassName( entityMode ); if ( tuplizerClassName == null ) { entityTuplizer = entityTuplizerFactory.constructDefaultTuplizer( entityMode, this, persistentClass );