From b0a0ca15c687b9ba8381962d05abbbb5da442bb4 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Tue, 23 Jul 2024 15:15:06 +0200 Subject: [PATCH] HHH-18410 Make use of getter/setter cache as much as possible --- .../internal/AbstractEntityInsertAction.java | 4 +- .../hibernate/engine/internal/Cascade.java | 21 ++++-- .../engine/internal/Collections.java | 3 +- .../internal/StatefulPersistenceContext.java | 8 +- .../engine/spi/PersistenceContext.java | 6 +- .../AbstractFlushingEventListener.java | 32 +++++--- .../internal/DefaultMergeEventListener.java | 3 +- .../util/collections/IdentityMap.java | 7 +- .../AbstractCompositeIdentifierMapping.java | 2 +- .../metamodel/mapping/AttributeMapping.java | 4 +- .../mapping/EmbeddableMappingType.java | 5 +- .../metamodel/mapping/ManagedMappingType.java | 4 +- .../internal/AbstractEmbeddableMapping.java | 37 ++++++++-- .../internal/EmbeddableMappingTypeImpl.java | 70 ++++++++++++------ .../internal/EmbeddedAttributeMapping.java | 4 +- .../mapping/internal/IdClassEmbeddable.java | 4 +- ...InverseNonAggregatedIdentifierMapping.java | 11 +-- .../NonAggregatedIdentifierMappingImpl.java | 4 +- .../mapping/internal/VirtualIdEmbeddable.java | 10 +-- .../entity/AbstractEntityPersister.java | 74 +++++++++++-------- .../persister/entity/EntityPersister.java | 2 +- ...onymousTupleEmbeddableValuedModelPart.java | 14 +--- .../AnonymousTupleEntityValuedModelPart.java | 8 +- .../org/hibernate/query/spi/QueryOptions.java | 5 +- .../internal/EntityInitializerImpl.java | 35 +++++---- .../entity/CompositeGeneratorBuilder.java | 5 +- .../org/hibernate/type/ComponentType.java | 13 +++- ...hancementCollectionInitializationTest.java | 2 +- 28 files changed, 239 insertions(+), 158 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/AbstractEntityInsertAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/AbstractEntityInsertAction.java index 437ad96b34..2cb4c5f6b0 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/AbstractEntityInsertAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/AbstractEntityInsertAction.java @@ -193,14 +193,14 @@ public abstract class AbstractEntityInsertAction extends EntityAction { if ( attribute.isPluralAttributeMapping() ) { addCollectionKey( attribute.asPluralAttributeMapping(), - attribute.getPropertyAccess().getGetter().get( object ), + descriptor.getValue( object, i ), persistenceContext ); } else if ( attribute.isEmbeddedAttributeMapping() ) { visitEmbeddedAttributeMapping( attribute.asEmbeddedAttributeMapping(), - attribute.getPropertyAccess().getGetter().get( object ), + descriptor.getValue( object, i ), persistenceContext ); } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/Cascade.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/Cascade.java index dacb946a53..ecf12dcb2a 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/internal/Cascade.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/Cascade.java @@ -90,12 +90,18 @@ public final class Cascade { LOG.tracev( "Processing cascade {0} for: {1}", action, persister.getEntityName() ); } final PersistenceContext persistenceContext = eventSource.getPersistenceContextInternal(); - final EntityEntry entry = persistenceContext.getEntry( parent ); - if ( entry != null - && entry.getLoadedState() == null - && entry.getStatus() == Status.MANAGED - && persister.getBytecodeEnhancementMetadata().isEnhancedForLazyLoading() ) { - return; + final boolean enhancedForLazyLoading = persister.getBytecodeEnhancementMetadata().isEnhancedForLazyLoading(); + final EntityEntry entry; + if ( enhancedForLazyLoading ) { + entry = persistenceContext.getEntry( parent ); + if ( entry != null + && entry.getLoadedState() == null + && entry.getStatus() == Status.MANAGED ) { + return; + } + } + else { + entry = null; } final Type[] types = persister.getPropertyTypes(); final String[] propertyNames = persister.getPropertyNames(); @@ -113,6 +119,7 @@ public final class Cascade { if ( style.doCascade( action ) ) { final Object child; if ( isUninitializedProperty ) { + assert enhancedForLazyLoading; // parent is a bytecode enhanced entity. // Cascade to an uninitialized, lazy value only if // parent is managed in the PersistenceContext. @@ -378,7 +385,7 @@ public final class Cascade { * @return True if the attribute represents a logical one to one association */ private static boolean isLogicalOneToOne(Type type) { - return type.isEntityType() && ( (EntityType) type ).isLogicalOneToOne(); + return type instanceof EntityType && ( (EntityType) type ).isLogicalOneToOne(); } private static boolean cascadeAssociationNow( diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/Collections.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/Collections.java index 8f0ef0e312..bb90f5bdbd 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/internal/Collections.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/Collections.java @@ -145,8 +145,7 @@ public final class Collections { Object entity, SessionImplementor session) { collection.setOwner( entity ); - final PersistenceContext persistenceContext = session.getPersistenceContextInternal(); - final CollectionEntry ce = persistenceContext.getCollectionEntry( collection ); + final CollectionEntry ce = session.getPersistenceContextInternal().getCollectionEntry( collection ); if ( ce == null ) { // refer to comment in StatefulPersistenceContext.addCollection() diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/StatefulPersistenceContext.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/StatefulPersistenceContext.java index 3d12016bd1..02affe87e3 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/internal/StatefulPersistenceContext.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/StatefulPersistenceContext.java @@ -414,7 +414,7 @@ public class StatefulPersistenceContext implements PersistenceContext { } @Override - public EntityHolderImpl getEntityHolder(EntityKey key) { + public @Nullable EntityHolderImpl getEntityHolder(EntityKey key) { return entitiesByKey == null ? null : entitiesByKey.get( key ); } @@ -534,7 +534,7 @@ public class StatefulPersistenceContext implements PersistenceContext { } @Override - public EntityHolderImpl removeEntityHolder(EntityKey key) { + public @Nullable EntityHolderImpl removeEntityHolder(EntityKey key) { final EntityHolderImpl holder; if ( entitiesByKey != null ) { holder = entitiesByKey.remove( key ); @@ -1333,8 +1333,8 @@ public class StatefulPersistenceContext implements PersistenceContext { */ @Override @Deprecated - public Map,CollectionEntry> getCollectionEntries() { - return getOrInitializeCollectionEntries(); + public @Nullable Map,CollectionEntry> getCollectionEntries() { + return collectionEntries; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/PersistenceContext.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/PersistenceContext.java index 09a54ca824..b60436330b 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/PersistenceContext.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/PersistenceContext.java @@ -524,11 +524,11 @@ public interface PersistenceContext { @Incubating EntityHolder addEntityHolder(EntityKey key, Object entity); - EntityHolder getEntityHolder(EntityKey key); + @Nullable EntityHolder getEntityHolder(EntityKey key); boolean containsEntityHolder(EntityKey key); - EntityHolder removeEntityHolder(EntityKey key); + @Nullable EntityHolder removeEntityHolder(EntityKey key); @Incubating void postLoad(JdbcValuesSourceProcessingState processingState, Consumer loadedConsumer); @@ -567,7 +567,7 @@ public interface PersistenceContext { * Doubly internal */ @Internal - Map,CollectionEntry> getCollectionEntries(); + @Nullable Map,CollectionEntry> getCollectionEntries(); /** * Execute some action on each entry of the collectionEntries map, optionally iterating on a defensive copy. diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractFlushingEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractFlushingEventListener.java index 4230c01f36..d43dcc9632 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractFlushingEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractFlushingEventListener.java @@ -14,6 +14,7 @@ import org.hibernate.action.internal.CollectionRecreateAction; import org.hibernate.action.internal.CollectionRemoveAction; import org.hibernate.action.internal.CollectionUpdateAction; import org.hibernate.action.internal.QueuedOperationCollectionAction; +import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.engine.internal.Cascade; import org.hibernate.engine.internal.CascadePoint; import org.hibernate.engine.internal.Collections; @@ -21,6 +22,7 @@ import org.hibernate.engine.jdbc.spi.JdbcCoordinator; import org.hibernate.engine.spi.ActionQueue; import org.hibernate.engine.spi.CascadingAction; import org.hibernate.engine.spi.CascadingActions; +import org.hibernate.engine.spi.CollectionEntry; import org.hibernate.engine.spi.CollectionKey; import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.PersistenceContext; @@ -35,6 +37,7 @@ import org.hibernate.event.spi.FlushEvent; import org.hibernate.event.spi.PersistContext; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.EntityPrinter; +import org.hibernate.internal.util.collections.IdentityMap; import org.hibernate.persister.entity.EntityPersister; import org.jboss.logging.Logger; @@ -218,7 +221,12 @@ public abstract class AbstractFlushingEventListener implements JpaBootstrapSensi // and reset reached, doupdate, etc. LOG.debug( "Dirty checking collections" ); - persistenceContext.forEachCollectionEntry( (pc,ce) -> ce.preFlush( pc ), true ); + final Map, CollectionEntry> collectionEntries = persistenceContext.getCollectionEntries(); + if ( collectionEntries != null ) { + for ( Map.Entry, CollectionEntry> entry : ( (IdentityMap, CollectionEntry>) collectionEntries ).entryArray() ) { + entry.getValue().preFlush( entry.getKey() ); + } + } } /** @@ -297,14 +305,20 @@ public abstract class AbstractFlushingEventListener implements JpaBootstrapSensi throws HibernateException { LOG.trace( "Processing unreferenced collections" ); - final int count = persistenceContext.getCollectionEntriesSize(); - - persistenceContext.forEachCollectionEntry( - (persistentCollection, collectionEntry) -> { - if ( !collectionEntry.isReached() && !collectionEntry.isIgnore() ) { - Collections.processUnreachableCollection( persistentCollection, session ); - } - }, true ); + final Map, CollectionEntry> collectionEntries = persistenceContext.getCollectionEntries(); + final int count; + if ( collectionEntries == null ) { + count = 0; + } + else { + count = collectionEntries.size(); + for ( Map.Entry, CollectionEntry> me : ( (IdentityMap, CollectionEntry>) collectionEntries ).entryArray() ) { + final CollectionEntry ce = me.getValue(); + if ( !ce.isReached() && !ce.isIgnore() ) { + Collections.processUnreachableCollection( me.getKey(), session ); + } + } + } // Schedule updates to collections: diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultMergeEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultMergeEventListener.java index 15b29938b6..24f7af0f2f 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultMergeEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultMergeEventListener.java @@ -353,8 +353,7 @@ public class DefaultMergeEventListener .getMappingMetamodel() .getCollectionDescriptor( collectionType.getRole() ); final CollectionEntry collectionEntry = getSession().getPersistenceContextInternal() - .getCollectionEntries() - .get( coll ); + .getCollectionEntry( coll ); if ( !coll.equalsSnapshot( persister ) ) { collectionEntry.resetStoredSnapshot( coll, coll.getSnapshot( persister ) ); } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/collections/IdentityMap.java b/hibernate-core/src/main/java/org/hibernate/internal/util/collections/IdentityMap.java index 308ede3d35..8d1f51908d 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/util/collections/IdentityMap.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/util/collections/IdentityMap.java @@ -24,7 +24,7 @@ public final class IdentityMap implements Map { private final LinkedHashMap,V> map; - private transient Entry,V>[] entryArray = null; + private transient Entry[] entryArray = null; /** * Return a new instance of this class, with iteration @@ -151,15 +151,14 @@ public final class IdentityMap implements Map { return set; } - @SuppressWarnings( {"unchecked"}) - public Entry[] entryArray() { + public Entry[] entryArray() { if ( entryArray == null ) { entryArray = new Entry[ map.size() ]; final Iterator, V>> itr = map.entrySet().iterator(); int i = 0; while ( itr.hasNext() ) { final Entry, V> me = itr.next(); - entryArray[i++] = new IdentityMapEntry( me.getKey().key, me.getValue() ); + entryArray[i++] = new IdentityMapEntry<>( me.getKey().key, me.getValue() ); } } return entryArray; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AbstractCompositeIdentifierMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AbstractCompositeIdentifierMapping.java index d2a38a79e8..8f8d17ac31 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AbstractCompositeIdentifierMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AbstractCompositeIdentifierMapping.java @@ -195,7 +195,7 @@ public abstract class AbstractCompositeIdentifierMapping else { for ( int i = 0; i < size; i++ ) { final AttributeMapping attributeMapping = embeddableTypeDescriptor.getAttributeMapping( i ); - final Object o = attributeMapping.getPropertyAccess().getGetter().get( value ); + final Object o = embeddableTypeDescriptor.getValue( value, i ); if ( attributeMapping instanceof ToOneAttributeMapping ) { final ToOneAttributeMapping toOneAttributeMapping = (ToOneAttributeMapping) attributeMapping; final ForeignKeyDescriptor fkDescriptor = toOneAttributeMapping.getForeignKeyDescriptor(); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/AttributeMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/AttributeMapping.java index 2273f489f0..4360c1cdae 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/AttributeMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/AttributeMapping.java @@ -56,14 +56,14 @@ public interface AttributeMapping * Convenient access to getting the value for this attribute from the declarer */ default Object getValue(Object container) { - return getPropertyAccess().getGetter().get( container ); + return getDeclaringType().getValue( container, getStateArrayPosition() ); } /** * Convenient access to setting the value for this attribute on the declarer */ default void setValue(Object container, Object value) { - getPropertyAccess().getSetter().set( container, value ); + getDeclaringType().setValue( container, getStateArrayPosition(), value ); } /** diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EmbeddableMappingType.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EmbeddableMappingType.java index 9d6e3478b4..8c18054183 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EmbeddableMappingType.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EmbeddableMappingType.java @@ -361,9 +361,8 @@ public interface EmbeddableMappingType extends ManagedMappingType, SelectableMap default int compare(Object value1, Object value2) { final AttributeMappingsList attributeMappings = getAttributeMappings(); for ( int i = 0; i < attributeMappings.size(); i++ ) { - AttributeMapping attributeMapping = attributeMappings.get( i ); - final Getter getter = attributeMapping.getPropertyAccess().getGetter(); - final int comparison = attributeMapping.compare( getter.get( value1 ), getter.get( value2 ) ); + final AttributeMapping attribute = attributeMappings.get( i ); + final int comparison = attribute.compare( attribute.getValue( value1 ), attribute.getValue( value2 ) ); if ( comparison != 0 ) { return comparison; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/ManagedMappingType.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/ManagedMappingType.java index 46a91a5376..bd62a5fe1e 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/ManagedMappingType.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/ManagedMappingType.java @@ -80,7 +80,7 @@ public interface ManagedMappingType extends MappingType, FetchableContainer { * Extract a specific attribute value from the entity instance, by position */ default Object getValue(Object instance, int position) { - return getAttributeMapping( position ).getValue( instance ); + return getAttributeMapping( position ).getPropertyAccess().getGetter().get( instance ); } /** @@ -92,7 +92,7 @@ public interface ManagedMappingType extends MappingType, FetchableContainer { * Inject a specific attribute value into the entity instance, by position */ default void setValue(Object instance, int position, Object value) { - getAttributeMapping( position ).setValue( instance, value ); + getAttributeMapping( position ).getPropertyAccess().getSetter().set( instance, value ); } default boolean anyRequiresAggregateColumnWriter() { diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractEmbeddableMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractEmbeddableMapping.java index 355c63a337..c0d7a9efe7 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractEmbeddableMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractEmbeddableMapping.java @@ -55,6 +55,7 @@ import org.hibernate.persister.entity.EntityPersister; import org.hibernate.property.access.internal.PropertyAccessStrategyBackRefImpl; import org.hibernate.property.access.spi.Getter; import org.hibernate.property.access.spi.PropertyAccess; +import org.hibernate.property.access.spi.Setter; import org.hibernate.sql.ast.tree.from.TableGroupProducer; import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.type.AnyType; @@ -75,6 +76,8 @@ public abstract class AbstractEmbeddableMapping implements EmbeddableMappingType EmbeddableMappingType.ConcreteEmbeddableType { final protected MutableAttributeMappingList attributeMappings; protected SelectableMappings selectableMappings; + protected Getter[] getterCache; + protected Setter[] setterCache; public AbstractEmbeddableMapping(MutableAttributeMappingList attributeMappings) { this.attributeMappings = attributeMappings; @@ -100,6 +103,16 @@ public abstract class AbstractEmbeddableMapping implements EmbeddableMappingType return true; } + @Override + public Object getValue(Object instance, int position) { + return getterCache[position].get( instance ); + } + + @Override + public void setValue(Object instance, int position, Object value) { + setterCache[position].set( instance, value ); + } + @Override public Object getDiscriminatorValue() { return null; @@ -127,10 +140,7 @@ public abstract class AbstractEmbeddableMapping implements EmbeddableMappingType protected Object[] getAttributeValues(Object compositeInstance) { final Object[] results = new Object[getNumberOfAttributeMappings()]; for ( int i = 0; i < results.length; i++ ) { - final Getter getter = getAttributeMapping( i ).getAttributeMetadata() - .getPropertyAccess() - .getGetter(); - results[i] = getter.get( compositeInstance ); + results[i] = getValue( compositeInstance, i ); } return results; } @@ -148,7 +158,7 @@ public abstract class AbstractEmbeddableMapping implements EmbeddableMappingType protected void setAttributeValues(Object component, Object[] values) { for ( int i = 0; i < values.length; i++ ) { - getAttributeMapping( i ).getPropertyAccess().getSetter().set( component, values[i] ); + setValue( component, i, values[i] ); } } @@ -253,6 +263,7 @@ public abstract class AbstractEmbeddableMapping implements EmbeddableMappingType } mappings.add( attributeMapping ); } + buildGetterSetterCache(); return true; } @@ -737,7 +748,7 @@ public abstract class AbstractEmbeddableMapping implements EmbeddableMappingType if ( attributeMapping instanceof PluralAttributeMapping ) { continue; } - final Object o = attributeMapping.getPropertyAccess().getGetter().get( value ); + final Object o = getValue( value, i ); span += attributeMapping.forEachJdbcValue( o, span + offset, x, y, valuesConsumer, session ); } } @@ -777,10 +788,24 @@ public abstract class AbstractEmbeddableMapping implements EmbeddableMappingType } this.selectableMappings = new SelectableMappingsImpl( selectableMappings.toArray( new SelectableMapping[0] ) ); + buildGetterSetterCache(); return true; } + protected void buildGetterSetterCache() { + final int propertySpan = attributeMappings.size(); + final Getter[] getterCache = new Getter[propertySpan]; + final Setter[] setterCache = new Setter[propertySpan]; + for ( int i = 0; i < propertySpan; i++ ) { + final PropertyAccess propertyAccess = attributeMappings.get( i ).getPropertyAccess(); + getterCache[i] = propertyAccess.getGetter(); + setterCache[i] = propertyAccess.getSetter(); + } + this.getterCache = getterCache; + this.setterCache = setterCache; + } + private static MutabilityPlan getMutabilityPlan(boolean updateable) { if ( updateable ) { return new MutabilityPlan<>() { diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddableMappingTypeImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddableMappingTypeImpl.java index 6e2f89566f..703d01afc2 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddableMappingTypeImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddableMappingTypeImpl.java @@ -49,6 +49,7 @@ import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping; import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.mapping.ModelPart; +import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.metamodel.mapping.SelectableConsumer; import org.hibernate.metamodel.mapping.SelectableMapping; import org.hibernate.metamodel.mapping.SelectableMappings; @@ -862,6 +863,7 @@ public class EmbeddableMappingTypeImpl extends AbstractEmbeddableMapping impleme return concreteEmbeddableByDiscriminator == null ? this : concreteEmbeddableByDiscriminator.get( discriminatorValue ); } + @Override public ConcreteEmbeddableType findSubtypeBySubclass(String subclassName) { return concreteEmbeddableBySubclass == null ? this : concreteEmbeddableBySubclass.get( subclassName ); } @@ -872,16 +874,6 @@ public class EmbeddableMappingTypeImpl extends AbstractEmbeddableMapping impleme return (Collection) (Collection) concreteEmbeddableBySubclass.values(); } - @Override - public Object getValue(Object instance, int position) { - final AttributeMapping attributeMapping = getAttributeMapping( position ); - final ConcreteEmbeddableType concreteEmbeddableType = findSubtypeBySubclass( instance.getClass().getName() ); - if ( concreteEmbeddableType.declaresAttribute( attributeMapping ) ) { - return attributeMapping.getValue( instance ); - } - return null; - } - @Override protected Object[] getAttributeValues(Object compositeInstance) { if ( !isPolymorphic() ) { @@ -893,16 +885,9 @@ public class EmbeddableMappingTypeImpl extends AbstractEmbeddableMapping impleme final ConcreteEmbeddableType concreteEmbeddableType = findSubtypeBySubclass( compositeInstance.getClass().getName() ); int i = 0; for ( ; i < numberOfAttributes; i++ ) { - final AttributeMapping attributeMapping = getAttributeMapping( i ); - if ( concreteEmbeddableType.declaresAttribute( attributeMapping ) ) { - final Getter getter = attributeMapping.getAttributeMetadata() - .getPropertyAccess() - .getGetter(); - results[i] = getter.get( compositeInstance ); - } - else { - results[i] = null; - } + results[i] = concreteEmbeddableType.declaresAttribute( i ) + ? getValue( compositeInstance, i ) + : null; } results[i] = compositeInstance.getClass().getName(); return results; @@ -920,7 +905,7 @@ public class EmbeddableMappingTypeImpl extends AbstractEmbeddableMapping impleme for ( int i = 0; i < getNumberOfAttributeMappings(); i++ ) { final AttributeMapping attributeMapping = getAttributeMapping( i ); if ( concreteEmbeddableType.declaresAttribute( attributeMapping ) ) { - attributeMapping.getPropertyAccess().getSetter().set( component, values[i] ); + setValue( component, i, values[i] ); } else if ( values[i] != null ) { throw new IllegalArgumentException( String.format( @@ -982,7 +967,7 @@ public class EmbeddableMappingTypeImpl extends AbstractEmbeddableMapping impleme if ( !attributeMapping.isPluralAttributeMapping() ) { final Object attributeValue = concreteEmbeddableType == null || !concreteEmbeddableType.declaresAttribute( attributeMapping ) ? null - : attributeMapping.getPropertyAccess().getGetter().get( domainValue ); + : getValue( domainValue, i ); span += attributeMapping.breakDownJdbcValues( attributeValue, offset + span, @@ -1001,6 +986,47 @@ public class EmbeddableMappingTypeImpl extends AbstractEmbeddableMapping impleme return span; } + @Override + public int forEachJdbcValue( + Object value, + int offset, + X x, + Y y, + JdbcValuesBiConsumer valuesConsumer, + SharedSessionContractImplementor session) { + int span = 0; + if ( value == null ) { + for ( int i = 0; i < attributeMappings.size(); i++ ) { + final AttributeMapping attributeMapping = attributeMappings.get( i ); + if ( attributeMapping instanceof PluralAttributeMapping ) { + continue; + } + span += attributeMapping.forEachJdbcValue( null, span + offset, x, y, valuesConsumer, session ); + } + if ( isPolymorphic() ) { + span += discriminatorMapping.forEachJdbcValue( null, offset + span, x, y, valuesConsumer, session ); + } + } + else { + final ConcreteEmbeddableType concreteEmbeddableType = findSubtypeBySubclass( value.getClass().getName() ); + for ( int i = 0; i < attributeMappings.size(); i++ ) { + final AttributeMapping attributeMapping = attributeMappings.get( i ); + if ( attributeMapping instanceof PluralAttributeMapping ) { + continue; + } + final Object attributeValue = concreteEmbeddableType == null || !concreteEmbeddableType.declaresAttribute( attributeMapping ) + ? null + : getValue( value, i ); + span += attributeMapping.forEachJdbcValue( attributeValue, span + offset, x, y, valuesConsumer, session ); + } + if ( isPolymorphic() ) { + final Object d = concreteEmbeddableType == null ? null : concreteEmbeddableType.getDiscriminatorValue(); + span += discriminatorMapping.forEachJdbcValue( d, offset + span, x, y, valuesConsumer, session ); + } + } + return span; + } + @Override public int decompose( Object domainValue, diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedAttributeMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedAttributeMapping.java index d8c1b3e701..9308988f03 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedAttributeMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedAttributeMapping.java @@ -143,7 +143,9 @@ public class EmbeddedAttributeMapping MappingModelCreationProcess creationProcess) { super( inverseModelPart.getFetchableName(), - -1, + inverseModelPart.asAttributeMapping() != null + ? inverseModelPart.asAttributeMapping().getStateArrayPosition() + : -1, inverseModelPart.getFetchableKey(), inverseModelPart.asAttributeMapping() != null ? inverseModelPart.asAttributeMapping().getAttributeMetadata() diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/IdClassEmbeddable.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/IdClassEmbeddable.java index fb7cf26c7e..ff555ce78c 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/IdClassEmbeddable.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/IdClassEmbeddable.java @@ -165,7 +165,7 @@ public class IdClassEmbeddable extends AbstractEmbeddableMapping implements Iden for ( int i = 0; i < propertyValues.length; i++ ) { final AttributeMapping attributeMapping = virtualIdEmbeddable.getAttributeMapping( i ); - final Object o = attributeMapping.getPropertyAccess().getGetter().get( entity ); + final Object o = attributeMapping.getValue( entity ); if ( o == null ) { final AttributeMapping idClassAttributeMapping = getAttributeMapping( i ); if ( idClassAttributeMapping.getPropertyAccess().getGetter().getReturnTypeClass().isPrimitive() ) { @@ -210,7 +210,7 @@ public class IdClassEmbeddable extends AbstractEmbeddableMapping implements Iden virtualIdEmbeddable.forEachAttribute( (position, virtualIdAttribute) -> { final AttributeMapping idClassAttribute = attributeMappings.get( position ); - Object o = idClassAttribute.getPropertyAccess().getGetter().get( id ); + Object o = idClassAttribute.getValue( id ); if ( virtualIdAttribute instanceof ToOneAttributeMapping && !( idClassAttribute instanceof ToOneAttributeMapping ) ) { final ToOneAttributeMapping toOneAttributeMapping = (ToOneAttributeMapping) virtualIdAttribute; final EntityPersister entityPersister = toOneAttributeMapping.getEntityMappingType() diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/InverseNonAggregatedIdentifierMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/InverseNonAggregatedIdentifierMapping.java index 1388833da5..5e47f34d21 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/InverseNonAggregatedIdentifierMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/InverseNonAggregatedIdentifierMapping.java @@ -205,7 +205,7 @@ public class InverseNonAggregatedIdentifierMapping extends EmbeddedAttributeMapp final Object[] propertyValues = new Object[embeddableTypeDescriptor.getNumberOfAttributeMappings()]; for ( int i = 0; i < propertyValues.length; i++ ) { final AttributeMapping attributeMapping = embeddableTypeDescriptor.getAttributeMapping( i ); - final Object o = attributeMapping.getPropertyAccess().getGetter().get( entity ); + final Object o = attributeMapping.getValue( entity ); if ( o == null ) { final AttributeMapping idClassAttributeMapping = identifierValueMapper.getAttributeMapping( i ); if ( idClassAttributeMapping.getPropertyAccess().getGetter().getReturnTypeClass().isPrimitive() ) { @@ -249,7 +249,7 @@ public class InverseNonAggregatedIdentifierMapping extends EmbeddedAttributeMapp for ( int position = 0; position < propertyValues.length; position++ ) { final AttributeMapping attribute = embeddableTypeDescriptor.getAttributeMapping( position ); final AttributeMapping mappedIdAttributeMapping = identifierValueMapper.getAttributeMapping( position ); - Object o = mappedIdAttributeMapping.getPropertyAccess().getGetter().get( id ); + Object o = mappedIdAttributeMapping.getValue( id ); if ( attribute instanceof ToOneAttributeMapping && !( mappedIdAttributeMapping instanceof ToOneAttributeMapping ) ) { final ToOneAttributeMapping toOneAttributeMapping = (ToOneAttributeMapping) attribute; final EntityPersister entityPersister = toOneAttributeMapping.getEntityMappingType() @@ -260,11 +260,8 @@ public class InverseNonAggregatedIdentifierMapping extends EmbeddedAttributeMapp // use the managed object i.e. proxy or initialized entity o = holder == null ? null : holder.getManagedObject(); if ( o == null ) { - o = entityDescriptor - .findAttributeMapping( toOneAttributeMapping.getAttributeName() ) - .getPropertyAccess() - .getGetter() - .get( entity ); + o = entityDescriptor.findAttributeMapping( toOneAttributeMapping.getAttributeName() ) + .getValue( entity ); } } propertyValues[position] = o; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/NonAggregatedIdentifierMappingImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/NonAggregatedIdentifierMappingImpl.java index 972478fe66..54871a77f9 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/NonAggregatedIdentifierMappingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/NonAggregatedIdentifierMappingImpl.java @@ -246,7 +246,7 @@ public class NonAggregatedIdentifierMappingImpl extends AbstractCompositeIdentif final Object[] propertyValues = new Object[embeddableTypeDescriptor.getNumberOfAttributeMappings()]; for ( int i = 0; i < propertyValues.length; i++ ) { final AttributeMapping attributeMapping = embeddableTypeDescriptor.getAttributeMapping( i ); - final Object o = attributeMapping.getPropertyAccess().getGetter().get( entity ); + final Object o = attributeMapping.getValue( entity ); if ( o == null ) { final AttributeMapping idClassAttributeMapping = identifierValueMapper.getAttributeMapping( i ); if ( idClassAttributeMapping.getPropertyAccess().getGetter().getReturnTypeClass().isPrimitive() ) { @@ -292,7 +292,7 @@ public class NonAggregatedIdentifierMappingImpl extends AbstractCompositeIdentif for ( int i = 0; i < propertyValues.length; i++ ) { final AttributeMapping attribute = embeddableTypeDescriptor.getAttributeMapping( i ); final AttributeMapping mappedIdAttributeMapping = identifierValueMapper.getAttributeMapping( i ); - Object o = mappedIdAttributeMapping.getPropertyAccess().getGetter().get( id ); + Object o = mappedIdAttributeMapping.getValue( id ); if ( attribute instanceof ToOneAttributeMapping && !( mappedIdAttributeMapping instanceof ToOneAttributeMapping ) ) { final ToOneAttributeMapping toOneAttributeMapping = (ToOneAttributeMapping) attribute; final EntityPersister entityPersister = toOneAttributeMapping.getEntityMappingType().getEntityPersister(); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/VirtualIdEmbeddable.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/VirtualIdEmbeddable.java index f5233d598c..d6595da637 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/VirtualIdEmbeddable.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/VirtualIdEmbeddable.java @@ -258,9 +258,8 @@ public class VirtualIdEmbeddable extends AbstractEmbeddableMapping implements Id else { final AttributeMappingsList attributeMappings = getAttributeMappings(); for ( int i = 0; i < attributeMappings.size(); i++ ) { - final AttributeMapping attributeMapping = attributeMappings.get( i ); - final Getter getter = attributeMapping.getPropertyAccess().getGetter(); - if ( !attributeMapping.areEqual( getter.get( one ), getter.get( other ), session ) ) { + final AttributeMapping attribute = attributeMappings.get( i ); + if ( !attribute.areEqual( attribute.getValue( one ), attribute.getValue( other ), session ) ) { return false; } } @@ -274,9 +273,8 @@ public class VirtualIdEmbeddable extends AbstractEmbeddableMapping implements Id if ( idClassEmbeddable != null ) { final AttributeMappingsList attributeMappings = idClassEmbeddable.getAttributeMappings(); for ( int i = 0; i < attributeMappings.size(); i++ ) { - final AttributeMapping attributeMapping = attributeMappings.get( i ); - final Getter getter = attributeMapping.getPropertyAccess().getGetter(); - final int comparison = attributeMapping.compare( getter.get( value1 ), getter.get( value2 ) ); + final AttributeMapping attribute = attributeMappings.get( i ); + final int comparison = attribute.compare( attribute.getValue( value1 ), attribute.getValue( value2 ) ); if ( comparison != 0 ) { return comparison; } 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 3c3e82d0bc..0df64d9bc6 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 @@ -225,6 +225,7 @@ import org.hibernate.persister.entity.mutation.UpdateCoordinatorNoOp; import org.hibernate.persister.entity.mutation.UpdateCoordinatorStandard; import org.hibernate.persister.internal.SqlFragmentPredicate; import org.hibernate.persister.spi.PersisterCreationContext; +import org.hibernate.property.access.spi.Getter; import org.hibernate.property.access.spi.PropertyAccess; import org.hibernate.property.access.spi.Setter; import org.hibernate.query.PathException; @@ -465,6 +466,9 @@ public abstract class AbstractEntityPersister private AttributeMappingsList attributeMappings; protected AttributeMappingsMap declaredAttributeMappings = AttributeMappingsMap.builder().build(); protected AttributeMappingsList staticFetchableList; + // We build a cache for getters and setters to avoid megamorphic calls + private Getter[] getterCache; + private Setter[] setterCache; private final String queryLoaderName; @@ -4491,23 +4495,19 @@ public abstract class AbstractEntityPersister accessOptimizer.setPropertyValues( object, values ); } else { - if ( hasSubclasses() ) { + final BytecodeEnhancementMetadata enhancementMetadata = entityMetamodel.getBytecodeEnhancementMetadata(); + final AttributeMappingsList attributeMappings = getAttributeMappings(); + if ( enhancementMetadata.isEnhancedForLazyLoading() ) { for ( int i = 0; i < attributeMappings.size(); i++ ) { final Object value = values[i]; if ( value != UNFETCHED_PROPERTY ) { - final Setter setter = attributeMappings.get( i ).getPropertyAccess().getSetter(); - setter.set( object, value ); + setterCache[i].set( object, value ); } } } else { - for ( int i = 0; i < staticFetchableList.size(); i++ ) { - final AttributeMapping attribute = staticFetchableList.get( i ); - final Object value = values[i]; - if ( value != UNFETCHED_PROPERTY ) { - final Setter setter = attribute.getPropertyAccess().getSetter(); - setter.set( object, value ); - } + for ( int i = 0; i < attributeMappings.size(); i++ ) { + setterCache[i].set( object, values[i] ); } } } @@ -4515,8 +4515,7 @@ public abstract class AbstractEntityPersister @Override public void setPropertyValue(Object object, int i, Object value) { - final String propertyName = getPropertyNames()[i]; - setPropertyValue( object, propertyName, value ); + setterCache[i].set( object, value ); } @Override @@ -4526,17 +4525,24 @@ public abstract class AbstractEntityPersister } else { final BytecodeEnhancementMetadata enhancementMetadata = entityMetamodel.getBytecodeEnhancementMetadata(); - final LazyAttributesMetadata lazyAttributesMetadata = enhancementMetadata.getLazyAttributesMetadata(); - final Object[] values = new Object[ getNumberOfAttributeMappings() ]; - for ( int i = 0; i < attributeMappings.size(); i++ ) { - final AttributeMapping attributeMapping = attributeMappings.get( i ); - final AttributeMetadata attributeMetadata = attributeMapping.getAttributeMetadata(); - if ( ! lazyAttributesMetadata.isLazyAttribute( attributeMapping.getAttributeName() ) - || enhancementMetadata.isAttributeLoaded( object, attributeMapping.getAttributeName() ) ) { - values[i] = attributeMetadata.getPropertyAccess().getGetter().get( object ); + final AttributeMappingsList attributeMappings = getAttributeMappings(); + final Object[] values = new Object[attributeMappings.size()]; + if ( enhancementMetadata.isEnhancedForLazyLoading() ) { + final LazyAttributesMetadata lazyAttributesMetadata = enhancementMetadata.getLazyAttributesMetadata(); + for ( int i = 0; i < attributeMappings.size(); i++ ) { + final AttributeMapping attributeMapping = attributeMappings.get( i ); + if ( !lazyAttributesMetadata.isLazyAttribute( attributeMapping.getAttributeName() ) + || enhancementMetadata.isAttributeLoaded( object, attributeMapping.getAttributeName() ) ) { + values[i] = getterCache[i].get( object ); + } + else { + values[i] = LazyPropertyInitializer.UNFETCHED_PROPERTY; + } } - else { - values[i] = LazyPropertyInitializer.UNFETCHED_PROPERTY; + } + else { + for ( int i = 0; i < attributeMappings.size(); i++ ) { + values[i] = getterCache[i].get( object ); } } @@ -4546,7 +4552,7 @@ public abstract class AbstractEntityPersister @Override public Object getPropertyValue(Object object, int i) { - return attributeMappings.get( i ).getAttributeMetadata().getPropertyAccess().getGetter().get( object ); + return getterCache[i].get( object ); } @Override @@ -4559,7 +4565,7 @@ public abstract class AbstractEntityPersister ManagedMappingType baseValueType = null; Object baseValue = null; if ( attributeMapping != null ) { - baseValue = attributeMapping.getAttributeMetadata().getPropertyAccess().getGetter().get( object ); + baseValue = getterCache[attributeMapping.getStateArrayPosition()].get( object ); if ( dotIndex != -1 ) { baseValueType = (ManagedMappingType) attributeMapping.getMappedType(); } @@ -4570,7 +4576,7 @@ public abstract class AbstractEntityPersister null ).asAttributeMapping(); if ( mapping != null ) { - baseValue = mapping.getAttributeMetadata().getPropertyAccess().getGetter().get( object ); + baseValue = mapping.getValue( object ); if ( dotIndex != -1 ) { baseValueType = (ManagedMappingType) mapping.getMappedType(); } @@ -4592,7 +4598,7 @@ public abstract class AbstractEntityPersister final int endIndex = nextDotIndex == -1 ? propertyName.length() : nextDotIndex; final AttributeMapping attributeMapping = baseValueType.findAttributeMapping( propertyName.substring( dotIndex + 1, endIndex ) ); - baseValue = attributeMapping.getAttributeMetadata().getPropertyAccess().getGetter().get( baseValue ); + baseValue = attributeMapping.getValue( baseValue ); baseValueType = nextDotIndex == -1 ? null : (ManagedMappingType) attributeMapping.getMappedType(); return getPropertyValue( baseValue, baseValueType, propertyName, nextDotIndex ); } @@ -4712,9 +4718,7 @@ public abstract class AbstractEntityPersister final Object[] result = new Object[attributeMappings.size()]; for ( int i = 0; i < attributeMappings.size(); i++ ) { - result[i] = attributeMappings.get( i ) - .getPropertyAccess().getGetter() - .getForInsert( entity, mergeMap, session ); + result[i] = getterCache[i].getForInsert( entity, mergeMap, session ); } return result; } @@ -4888,8 +4892,7 @@ public abstract class AbstractEntityPersister @Override public void setPropertyValue(Object object, String propertyName, Object value) { final AttributeMapping attributeMapping = findSubPart( propertyName, this ).asAttributeMapping(); - final AttributeMetadata attributeMetadata = attributeMapping.getAttributeMetadata(); - attributeMetadata.getPropertyAccess().getSetter().set( object, value ); + setterCache[attributeMapping.getStateArrayPosition()].set( object, value ); } public static int getTableId(String tableName, String[] tables) { @@ -6013,6 +6016,15 @@ public abstract class AbstractEntityPersister builder.add( am ); } this.attributeMappings = builder.build(); + final Getter[] getters = new Getter[attributeMappings.size()]; + final Setter[] setters = new Setter[attributeMappings.size()]; + for ( int i = 0; i < attributeMappings.size(); i++ ) { + final PropertyAccess propertyAccess = attributeMappings.get( i ).getAttributeMetadata().getPropertyAccess(); + getters[i] = propertyAccess.getGetter(); + setters[i] = propertyAccess.getSetter(); + } + this.getterCache = getters; + this.setterCache = setters; // subclasses? it depends on the usage } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java index afb3cffcbe..a86e5f133d 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java @@ -529,7 +529,7 @@ public interface EntityPersister extends EntityMappingType, EntityMutationTarget else { for ( int i = 0; i < getNumberOfAttributeMappings(); i++ ) { final AttributeMapping attributeMapping = getAttributeMapping( i ); - final Object attributeValue = attributeMapping.getPropertyAccess().getGetter().get( domainValue ); + final Object attributeValue = attributeMapping.getValue( domainValue ); span += attributeMapping.breakDownJdbcValues( attributeValue, offset + span, diff --git a/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleEmbeddableValuedModelPart.java b/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleEmbeddableValuedModelPart.java index c30c41e9e0..932baaa717 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleEmbeddableValuedModelPart.java +++ b/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleEmbeddableValuedModelPart.java @@ -235,28 +235,22 @@ public class AnonymousTupleEmbeddableValuedModelPart implements EmbeddableValued @Override public Object[] getValues(Object instance) { - return existingModelPartContainer.getEmbeddableTypeDescriptor() - .getValues( instance ); + return existingModelPartContainer.getEmbeddableTypeDescriptor().getValues( instance ); } @Override public Object getValue(Object instance, int position) { - return existingModelPartContainer.getEmbeddableTypeDescriptor() - .getAttributeMapping( position ) - .getValue( instance ); + return existingModelPartContainer.getEmbeddableTypeDescriptor().getValue( instance, position ); } @Override public void setValues(Object instance, Object[] resolvedValues) { - existingModelPartContainer.getEmbeddableTypeDescriptor() - .setValues( instance, resolvedValues ); + existingModelPartContainer.getEmbeddableTypeDescriptor().setValues( instance, resolvedValues ); } @Override public void setValue(Object instance, int position, Object value) { - existingModelPartContainer.getEmbeddableTypeDescriptor() - .getAttributeMapping( position ) - .setValue( instance, value ); + existingModelPartContainer.getEmbeddableTypeDescriptor().setValue( instance, position, value ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleEntityValuedModelPart.java b/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleEntityValuedModelPart.java index 5bda777f23..dc73c84a40 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleEntityValuedModelPart.java +++ b/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleEntityValuedModelPart.java @@ -198,9 +198,7 @@ public class AnonymousTupleEntityValuedModelPart @Override public Object getValue(Object instance, int position) { - return delegate.getEntityMappingType() - .getAttributeMapping( position ) - .getValue( instance ); + return delegate.getEntityMappingType().getValue( instance, position ); } @Override @@ -210,9 +208,7 @@ public class AnonymousTupleEntityValuedModelPart @Override public void setValue(Object instance, int position, Object value) { - delegate.getEntityMappingType() - .getAttributeMapping( position ) - .setValue( instance, value ); + delegate.getEntityMappingType().setValue( instance, position, value ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/query/spi/QueryOptions.java b/hibernate-core/src/main/java/org/hibernate/query/spi/QueryOptions.java index c6c265a9e0..1d03d33d9c 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/spi/QueryOptions.java +++ b/hibernate-core/src/main/java/org/hibernate/query/spi/QueryOptions.java @@ -12,6 +12,7 @@ import java.util.Set; import jakarta.persistence.CacheRetrieveMode; import jakarta.persistence.CacheStoreMode; +import org.checkerframework.checker.nullness.qual.Nullable; import org.hibernate.CacheMode; import org.hibernate.FlushMode; @@ -57,13 +58,13 @@ public interface QueryOptions { * Transformer applied to the query to transform the structure of each "row" * in the results */ - TupleTransformer getTupleTransformer(); + @Nullable TupleTransformer getTupleTransformer(); /** * Transformer applied to the query to transform the structure of the * overall results */ - ResultListTransformer getResultListTransformer(); + @Nullable ResultListTransformer getResultListTransformer(); /** * Should results from the query be cached? diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityInitializerImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityInitializerImpl.java index 3041d6ca28..4da936d3f2 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityInitializerImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityInitializerImpl.java @@ -72,6 +72,7 @@ import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingOptions; import org.hibernate.sql.results.jdbc.spi.RowProcessingState; import org.hibernate.stat.spi.StatisticsImplementor; import org.hibernate.type.Type; +import org.hibernate.type.descriptor.java.MutabilityPlan; import org.checkerframework.checker.nullness.qual.EnsuresNonNull; import org.checkerframework.checker.nullness.qual.Nullable; @@ -124,6 +125,7 @@ public class EntityInitializerImpl extends AbstractInitializer[][] assemblers; private final Initializer[][] subInitializers; + private final MutabilityPlan[][] updatableAttributeMutabilityPlans; public static class EntityInitializerData extends InitializerData { @@ -235,10 +237,13 @@ public class EntityInitializerImpl extends AbstractInitializer subMappingTypes = rootEntityDescriptor.getSubMappingTypes(); final DomainResultAssembler[][] assemblers = new DomainResultAssembler[subMappingTypes.size() + 1][]; final Initializer[][] subInitializers = new Initializer[subMappingTypes.size() + 1][]; + final MutabilityPlan[][] updatableAttributeMutabilityPlans = new MutabilityPlan[subMappingTypes.size() + 1][]; assemblers[rootEntityDescriptor.getSubclassId()] = new DomainResultAssembler[rootEntityDescriptor.getNumberOfFetchables()]; + updatableAttributeMutabilityPlans[rootEntityDescriptor.getSubclassId()] = new MutabilityPlan[rootEntityDescriptor.getNumberOfAttributeMappings()]; for ( EntityMappingType subMappingType : subMappingTypes ) { assemblers[subMappingType.getSubclassId()] = new DomainResultAssembler[subMappingType.getNumberOfFetchables()]; + updatableAttributeMutabilityPlans[subMappingType.getSubclassId()] = new MutabilityPlan[subMappingType.getNumberOfAttributeMappings()]; } final int size = entityDescriptor.getNumberOfFetchables(); @@ -262,8 +267,13 @@ public class EntityInitializerImpl extends AbstractInitializer[size]; @@ -285,6 +295,7 @@ public class EntityInitializerImpl extends AbstractInitializer[] updatableAttributeMutabilityPlan = updatableAttributeMutabilityPlans[containerDescriptor.getSubclassId()]; + for ( int i = 0; i < updatableAttributeMutabilityPlan.length; i++ ) { + final Object sourceValue = source[i]; + if ( updatableAttributeMutabilityPlan[i] != null + && sourceValue != LazyPropertyInitializer.UNFETCHED_PROPERTY + && sourceValue != PropertyAccessStrategyBackRefImpl.UNKNOWN ) { + target[i] = updatableAttributeMutabilityPlan[i].deepCopy( source[i] ); } } } - @SuppressWarnings("unchecked") - private static Object copy(AttributeMetadata attributeMetadata, Object sourceValue) { - return sourceValue == LazyPropertyInitializer.UNFETCHED_PROPERTY - || sourceValue == PropertyAccessStrategyBackRefImpl.UNKNOWN - ? sourceValue - : attributeMetadata.getMutabilityPlan().deepCopy( sourceValue ); - } - @Override public ModelPart getInitializedPart() { return referencedModelPart; diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/CompositeGeneratorBuilder.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/CompositeGeneratorBuilder.java index aa507b68e8..c5e2afddcf 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/entity/CompositeGeneratorBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/CompositeGeneratorBuilder.java @@ -183,11 +183,10 @@ class CompositeGeneratorBuilder { for ( int i = 0; i < size; i++ ) { final Generator generator = generators.get(i); if ( generator != null ) { - final AttributeMapping attributeMapping = descriptor.getAttributeMapping(i); - final Object value = attributeMapping.getPropertyAccess().getGetter().get( currentValue ); + final Object value = descriptor.getValue( currentValue, i ); final Object generatedValue = ((BeforeExecutionGenerator) generator) .generate( session, owner, value, eventType ); - attributeMapping.getPropertyAccess().getSetter().set( currentValue, generatedValue ); + descriptor.setValue( currentValue, i, generatedValue ); } } return currentValue; diff --git a/hibernate-core/src/main/java/org/hibernate/type/ComponentType.java b/hibernate-core/src/main/java/org/hibernate/type/ComponentType.java index 1ba92b36f6..b970319165 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/ComponentType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/ComponentType.java @@ -417,7 +417,18 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen return ((Object[]) component)[i]; } else { - return embeddableTypeDescriptor().getValue( component, i ); + final EmbeddableMappingType embeddableMappingType = embeddableTypeDescriptor(); + if ( embeddableMappingType.isPolymorphic() ) { + final EmbeddableMappingType.ConcreteEmbeddableType concreteEmbeddableType = embeddableMappingType.findSubtypeBySubclass( + component.getClass().getName() + ); + return concreteEmbeddableType.declaresAttribute( i ) + ? embeddableMappingType.getValue( component, i ) + : null; + } + else { + return embeddableMappingType.getValue( component, i ); + } } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/proxy/LazyProxyBytecodeEnhancementCollectionInitializationTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/proxy/LazyProxyBytecodeEnhancementCollectionInitializationTest.java index 0070b0007c..e396c67f4a 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/proxy/LazyProxyBytecodeEnhancementCollectionInitializationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/lazy/proxy/LazyProxyBytecodeEnhancementCollectionInitializationTest.java @@ -76,7 +76,7 @@ public class LazyProxyBytecodeEnhancementCollectionInitializationTest { Parent parent = s.getReference( Parent.class, 1 ); assertThat( Hibernate.isPropertyInitialized( parent, "children") ).isFalse(); assertThat( s.unwrap( SessionImplementor.class ).getPersistenceContext().getCollectionEntries() ) - .isEmpty(); + .isNullOrEmpty(); // Accessing a collection property on a lazy proxy initializes the property and instantiates the collection, // but does not initialize the collection.