From 71541679e8a80fe52dd7095b5c4b683a496d9471 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Sat, 25 Mar 2023 15:30:45 +0100 Subject: [PATCH] HHH-16372 Fix NPEs in some Bindable implementations that operate on values --- .../AbstractCompositeIdentifierMapping.java | 55 ++++--- .../mapping/EmbeddableValuedModelPart.java | 58 +++++++ .../internal/AbstractEmbeddableMapping.java | 80 ++++++++-- .../internal/CompoundNaturalIdMapping.java | 101 ++++++++---- ...criminatedAssociationAttributeMapping.java | 38 +++-- .../internal/EmbeddedAttributeMapping.java | 76 --------- .../internal/EmbeddedCollectionPart.java | 36 ----- .../EmbeddedIdentifierMappingImpl.java | 40 ----- .../mapping/internal/IdClassEmbeddable.java | 45 ------ .../mapping/internal/VirtualIdEmbeddable.java | 16 -- .../TupleMappingModelExpressible.java | 69 ++++++-- ...onymousTupleEmbeddableValuedModelPart.java | 151 +++++++++++++----- 12 files changed, 421 insertions(+), 344 deletions(-) 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 2800f061bc..d6cf57370c 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 @@ -88,11 +88,6 @@ public abstract class AbstractCompositeIdentifierMapping return getPartMappingType(); } - @Override - public JavaType getJavaType() { - return getPartMappingType().getMappedJavaType(); - } - @Override public String getContainingTableExpression() { return tableExpression; @@ -188,28 +183,36 @@ public abstract class AbstractCompositeIdentifierMapping int span = 0; final EmbeddableMappingType embeddableTypeDescriptor = getEmbeddableTypeDescriptor(); final int size = embeddableTypeDescriptor.getNumberOfAttributeMappings(); - for ( int i = 0; i < size; i++ ) { - final AttributeMapping attributeMapping = embeddableTypeDescriptor.getAttributeMapping( i ); - final Object o = attributeMapping.getPropertyAccess().getGetter().get( value ); - if ( attributeMapping instanceof ToOneAttributeMapping ) { - final ToOneAttributeMapping toOneAttributeMapping = (ToOneAttributeMapping) attributeMapping; - final ForeignKeyDescriptor fkDescriptor = toOneAttributeMapping.getForeignKeyDescriptor(); - final Object identifier = fkDescriptor.getAssociationKeyFromSide( - o, - toOneAttributeMapping.getSideNature().inverse(), - session - ); - span += fkDescriptor.forEachJdbcValue( - identifier, - span + offset, - x, - y, - valuesConsumer, - session - ); + if ( value == null ) { + for ( int i = 0; i < size; i++ ) { + final AttributeMapping attributeMapping = embeddableTypeDescriptor.getAttributeMapping( i ); + span += attributeMapping.forEachJdbcValue( null, span + offset, x, y, valuesConsumer, session ); } - else { - span += attributeMapping.forEachJdbcValue( o, span + offset, x, y, valuesConsumer, session ); + } + else { + for ( int i = 0; i < size; i++ ) { + final AttributeMapping attributeMapping = embeddableTypeDescriptor.getAttributeMapping( i ); + final Object o = attributeMapping.getPropertyAccess().getGetter().get( value ); + if ( attributeMapping instanceof ToOneAttributeMapping ) { + final ToOneAttributeMapping toOneAttributeMapping = (ToOneAttributeMapping) attributeMapping; + final ForeignKeyDescriptor fkDescriptor = toOneAttributeMapping.getForeignKeyDescriptor(); + final Object identifier = fkDescriptor.getAssociationKeyFromSide( + o, + toOneAttributeMapping.getSideNature().inverse(), + session + ); + span += fkDescriptor.forEachJdbcValue( + identifier, + span + offset, + x, + y, + valuesConsumer, + session + ); + } + else { + span += attributeMapping.forEachJdbcValue( o, span + offset, x, y, valuesConsumer, session ); + } } } return span; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EmbeddableValuedModelPart.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EmbeddableValuedModelPart.java index 85083eabd0..307b8b8ef7 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EmbeddableValuedModelPart.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EmbeddableValuedModelPart.java @@ -21,6 +21,7 @@ import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.ast.tree.from.TableGroupJoinProducer; import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.FetchableContainer; +import org.hibernate.type.descriptor.java.JavaType; /** * Describes the mapping of an embeddable (composite). @@ -37,6 +38,11 @@ public interface EmbeddableValuedModelPart extends ValuedModelPart, Fetchable, F return getEmbeddableTypeDescriptor(); } + @Override + default JavaType getJavaType() { + return getEmbeddableTypeDescriptor().getJavaType(); + } + @Override default ModelPart findSubPart(String name, EntityMappingType treatTargetType) { return getEmbeddableTypeDescriptor().findSubPart( name, treatTargetType ); @@ -83,6 +89,43 @@ public interface EmbeddableValuedModelPart extends ValuedModelPart, Fetchable, F return getEmbeddableTypeDescriptor().forEachJdbcValue( value, offset, x, y, valuesConsumer, session ); } + @Override + default int breakDownJdbcValues( + Object domainValue, + int offset, + X x, + Y y, + JdbcValueBiConsumer valueConsumer, + SharedSessionContractImplementor session) { + return getEmbeddableTypeDescriptor().breakDownJdbcValues( domainValue, offset, x, y, valueConsumer, session ); + } + + @Override + default int decompose( + Object domainValue, + int offset, + X x, + Y y, + JdbcValueBiConsumer valueConsumer, + SharedSessionContractImplementor session) { + return getEmbeddableTypeDescriptor().decompose( domainValue, offset, x, y, valueConsumer, session ); + } + + @Override + default int getNumberOfFetchables() { + return getEmbeddableTypeDescriptor().getNumberOfAttributeMappings(); + } + + @Override + default Fetchable getFetchable(int position) { + return getEmbeddableTypeDescriptor().getFetchable( position ); + } + + @Override + default int getSelectableIndex(String selectableName) { + return getEmbeddableTypeDescriptor().getSelectableIndex( selectableName ); + } + @Override default SelectableMapping getSelectable(int columnIndex) { return getEmbeddableTypeDescriptor().getSelectable( columnIndex ); @@ -93,6 +136,21 @@ public interface EmbeddableValuedModelPart extends ValuedModelPart, Fetchable, F return getEmbeddableTypeDescriptor().forEachSelectable( offset, consumer ); } + @Override + default void forEachInsertable(SelectableConsumer consumer) { + getEmbeddableTypeDescriptor().forEachInsertable( 0, consumer ); + } + + @Override + default void forEachUpdatable(SelectableConsumer consumer) { + getEmbeddableTypeDescriptor().forEachUpdatable( 0, consumer ); + } + + @Override + default boolean hasPartitionedSelectionMapping() { + return getEmbeddableTypeDescriptor().hasPartitionedSelectionMapping(); + } + @Override default int forEachDisassembledJdbcValue( Object value, 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 266c060631..a886c37c3f 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 @@ -574,8 +574,35 @@ public abstract class AbstractEmbeddableMapping implements EmbeddableMappingType forEachAttributeMapping( consumer ); } + @Override + public int breakDownJdbcValues( + Object domainValue, + int offset, + X x, + Y y, + JdbcValueBiConsumer valueConsumer, SharedSessionContractImplementor session) { + int span = 0; + if ( domainValue == null ) { + for ( int i = 0; i < attributeMappings.size(); i++ ) { + final AttributeMapping attribute = attributeMappings.get( i ); + span += attribute.breakDownJdbcValues( null, offset + span, x, y, valueConsumer, session ); + } + } + else { + for ( int i = 0; i < attributeMappings.size(); i++ ) { + final AttributeMapping attribute = attributeMappings.get( i ); + final Object attributeValue = attribute.getValue( domainValue ); + span += attribute.breakDownJdbcValues( attributeValue, offset + span, x, y, valueConsumer, session ); + } + } + return span; + } + @Override public Object disassemble(Object value, SharedSessionContractImplementor session) { + if ( value == null ) { + return null; + } final int size = attributeMappings.size(); final Object[] result = new Object[ size ]; for ( int i = 0; i < size; i++ ) { @@ -590,9 +617,16 @@ public abstract class AbstractEmbeddableMapping implements EmbeddableMappingType @Override public void addToCacheKey(MutableCacheKeyBuilder cacheKey, Object value, SharedSessionContractImplementor session) { final int size = attributeMappings.size(); - for ( int i = 0; i < size; i++ ) { - final AttributeMapping attributeMapping = attributeMappings.get( i ); - attributeMapping.addToCacheKey( cacheKey, attributeMapping.getValue( value ), session ); + if ( value == null ) { + for ( int i = 0; i < size; i++ ) { + attributeMappings.get( i ).addToCacheKey( cacheKey, null, session ); + } + } + else { + for ( int i = 0; i < size; i++ ) { + final AttributeMapping attributeMapping = attributeMappings.get( i ); + attributeMapping.addToCacheKey( cacheKey, attributeMapping.getValue( value ), session ); + } } } @@ -604,11 +638,19 @@ public abstract class AbstractEmbeddableMapping implements EmbeddableMappingType Y y, JdbcValuesBiConsumer valuesConsumer, SharedSessionContractImplementor session) { - final Object[] values = (Object[]) value; int span = 0; - for ( int i = 0; i < attributeMappings.size(); i++ ) { - final AttributeMapping mapping = attributeMappings.get( i ); - span += mapping.forEachDisassembledJdbcValue( values[i], span + offset, x, y, valuesConsumer, session ); + if ( value == null ) { + for ( int i = 0; i < attributeMappings.size(); i++ ) { + final AttributeMapping mapping = attributeMappings.get( i ); + span += mapping.forEachDisassembledJdbcValue( null, span + offset, x, y, valuesConsumer, session ); + } + } + else { + final Object[] values = (Object[]) value; + for ( int i = 0; i < attributeMappings.size(); i++ ) { + final AttributeMapping mapping = attributeMappings.get( i ); + span += mapping.forEachDisassembledJdbcValue( values[i], span + offset, x, y, valuesConsumer, session ); + } } return span; } @@ -622,14 +664,24 @@ public abstract class AbstractEmbeddableMapping implements EmbeddableMappingType JdbcValuesBiConsumer valuesConsumer, SharedSessionContractImplementor session) { int span = 0; - - for ( int i = 0; i < attributeMappings.size(); i++ ) { - final AttributeMapping attributeMapping = attributeMappings.get( i ); - if ( attributeMapping instanceof PluralAttributeMapping ) { - continue; + 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 ); + } + } + else { + for ( int i = 0; i < attributeMappings.size(); i++ ) { + final AttributeMapping attributeMapping = attributeMappings.get( i ); + if ( attributeMapping instanceof PluralAttributeMapping ) { + continue; + } + final Object o = attributeMapping.getPropertyAccess().getGetter().get( value ); + span += attributeMapping.forEachJdbcValue( o, span + offset, x, y, valuesConsumer, session ); } - final Object o = attributeMapping.getPropertyAccess().getGetter().get( value ); - span += attributeMapping.forEachJdbcValue( o, span + offset, x, y, valuesConsumer, session ); } return span; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/CompoundNaturalIdMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/CompoundNaturalIdMapping.java index f66ac60d54..f88b391d33 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/CompoundNaturalIdMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/CompoundNaturalIdMapping.java @@ -326,16 +326,23 @@ public class CompoundNaturalIdMapping extends AbstractNaturalIdMapping implement for ( int i = 0; i < attributes.size(); i++ ) { span += attributes.get( i ).breakDownJdbcValues( null, offset + span, x, y, valueConsumer, session ); } - return span; } + else { + assert domainValue instanceof Object[]; - assert domainValue instanceof Object[]; + final Object[] values = (Object[]) domainValue; + assert values.length == attributes.size(); - final Object[] values = (Object[]) domainValue; - assert values.length == attributes.size(); - - for ( int i = 0; i < attributes.size(); i++ ) { - span += attributes.get( i ).breakDownJdbcValues( values[ i ], offset + span, x, y, valueConsumer, session ); + for ( int i = 0; i < attributes.size(); i++ ) { + span += attributes.get( i ).breakDownJdbcValues( + values[i], + offset + span, + x, + y, + valueConsumer, + session + ); + } } return span; } @@ -379,6 +386,9 @@ public class CompoundNaturalIdMapping extends AbstractNaturalIdMapping implement @Override public Object disassemble(Object value, SharedSessionContractImplementor session) { + if ( value == null ) { + return null; + } assert value instanceof Object[]; final Object[] incoming = (Object[]) value; @@ -396,13 +406,20 @@ public class CompoundNaturalIdMapping extends AbstractNaturalIdMapping implement @Override public void addToCacheKey(MutableCacheKeyBuilder cacheKey, Object value, SharedSessionContractImplementor session) { - assert value instanceof Object[]; + if ( value == null ) { + for ( int i = 0; i < attributes.size(); i++ ) { + attributes.get( i ).addToCacheKey( cacheKey, null, session ); + } + } + else { + assert value instanceof Object[]; - final Object[] values = (Object[]) value; - assert values.length == attributes.size(); + final Object[] values = (Object[]) value; + assert values.length == attributes.size(); - for ( int i = 0; i < attributes.size(); i++ ) { - attributes.get( i ).addToCacheKey( cacheKey, values[i], session ); + for ( int i = 0; i < attributes.size(); i++ ) { + attributes.get( i ).addToCacheKey( cacheKey, values[i], session ); + } } } @@ -414,14 +431,36 @@ public class CompoundNaturalIdMapping extends AbstractNaturalIdMapping implement Y y, JdbcValuesBiConsumer valuesConsumer, SharedSessionContractImplementor session) { - assert value instanceof Object[]; - - final Object[] incoming = (Object[]) value; - assert incoming.length == attributes.size(); int span = 0; - for ( int i = 0; i < attributes.size(); i++ ) { - final SingularAttributeMapping attribute = attributes.get( i ); - span += attribute.forEachDisassembledJdbcValue( incoming[ i ], span + offset, x, y, valuesConsumer, session ); + if ( value == null ) { + for ( int i = 0; i < attributes.size(); i++ ) { + final SingularAttributeMapping attribute = attributes.get( i ); + span += attribute.forEachDisassembledJdbcValue( + null, + span + offset, + x, + y, + valuesConsumer, + session + ); + } + } + else { + assert value instanceof Object[]; + + final Object[] incoming = (Object[]) value; + assert incoming.length == attributes.size(); + for ( int i = 0; i < attributes.size(); i++ ) { + final SingularAttributeMapping attribute = attributes.get( i ); + span += attribute.forEachDisassembledJdbcValue( + incoming[i], + span + offset, + x, + y, + valuesConsumer, + session + ); + } } return span; } @@ -434,15 +473,23 @@ public class CompoundNaturalIdMapping extends AbstractNaturalIdMapping implement Y y, JdbcValuesBiConsumer valuesConsumer, SharedSessionContractImplementor session) { - assert value instanceof Object[]; - - final Object[] incoming = (Object[]) value; - assert incoming.length == attributes.size(); - int span = 0; - for ( int i = 0; i < attributes.size(); i++ ) { - final SingularAttributeMapping attribute = attributes.get( i ); - span += attribute.forEachJdbcValue( incoming[ i ], span + offset, x, y, valuesConsumer, session ); + if ( value == null ) { + for ( int i = 0; i < attributes.size(); i++ ) { + final SingularAttributeMapping attribute = attributes.get( i ); + span += attribute.forEachJdbcValue( null, span + offset, x, y, valuesConsumer, session ); + } + } + else { + assert value instanceof Object[]; + + final Object[] incoming = (Object[]) value; + assert incoming.length == attributes.size(); + + for ( int i = 0; i < attributes.size(); i++ ) { + final SingularAttributeMapping attribute = attributes.get( i ); + span += attribute.forEachJdbcValue( incoming[i], span + offset, x, y, valuesConsumer, session ); + } } return span; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedAssociationAttributeMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedAssociationAttributeMapping.java index 366e40bb78..de0816aab4 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedAssociationAttributeMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedAssociationAttributeMapping.java @@ -240,18 +240,20 @@ public class DiscriminatedAssociationAttributeMapping @Override public void addToCacheKey(MutableCacheKeyBuilder cacheKey, Object value, SharedSessionContractImplementor session) { if ( value == null ) { - return ; + cacheKey.addValue( null ); + cacheKey.addHashCode( 0 ); } + else { + final EntityMappingType concreteMappingType = determineConcreteType( value, session ); - final EntityMappingType concreteMappingType = determineConcreteType( value, session ); + final Object discriminator = discriminatorMapping + .getModelPart() + .resolveDiscriminatorForEntityType( concreteMappingType ); + discriminatorMapping.getDiscriminatorPart().addToCacheKey( cacheKey, discriminator, session ); - final Object discriminator = discriminatorMapping - .getModelPart() - .resolveDiscriminatorForEntityType( concreteMappingType ); - discriminatorMapping.getDiscriminatorPart().addToCacheKey( cacheKey, discriminator, session ); - - final EntityIdentifierMapping identifierMapping = concreteMappingType.getIdentifierMapping(); - identifierMapping.addToCacheKey( cacheKey, identifierMapping.getIdentifier( value ), session ); + final EntityIdentifierMapping identifierMapping = concreteMappingType.getIdentifierMapping(); + identifierMapping.addToCacheKey( cacheKey, identifierMapping.getIdentifier( value ), session ); + } } private EntityMappingType determineConcreteType(Object entity, SharedSessionContractImplementor session) { @@ -290,7 +292,23 @@ public class DiscriminatedAssociationAttributeMapping Y y, JdbcValuesBiConsumer valuesConsumer, SharedSessionContractImplementor session) { - if ( value != null ) { + if ( value == null ) { + valuesConsumer.consume( + offset, + x, + y, + null, + discriminatorMapping.getDiscriminatorPart().getJdbcMapping() + ); + valuesConsumer.consume( + offset + 1, + x, + y, + null, + discriminatorMapping.getKeyPart().getJdbcMapping() + ); + } + else { if ( value.getClass().isArray() ) { final Object[] values = (Object[]) value; valuesConsumer.consume( 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 194830ca23..fa544c9f15 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 @@ -184,53 +184,6 @@ public class EmbeddedAttributeMapping return parentInjectionAttributePropertyAccess; } - @Override - public int compare(Object value1, Object value2) { - return super.compare( value1, value2 ); - } - - @Override - public int forEachSelectable(int offset, SelectableConsumer consumer) { - return getEmbeddableTypeDescriptor().forEachSelectable( offset, consumer ); - } - - @Override - public void forEachInsertable(SelectableConsumer consumer) { - getEmbeddableTypeDescriptor().forEachInsertable( 0, consumer ); - } - - @Override - public void forEachUpdatable(SelectableConsumer consumer) { - getEmbeddableTypeDescriptor().forEachUpdatable( 0, consumer ); - } - - @Override - public int breakDownJdbcValues( - Object domainValue, - int offset, - X x, - Y y, - JdbcValueBiConsumer valueConsumer, - SharedSessionContractImplementor session) { - return getEmbeddableTypeDescriptor().breakDownJdbcValues( domainValue, offset, x, y, valueConsumer, session ); - } - - @Override - public int decompose( - Object domainValue, - int offset, - X x, - Y y, - JdbcValueBiConsumer valueConsumer, - SharedSessionContractImplementor session) { - return getEmbeddableTypeDescriptor().decompose( domainValue, offset, x, y, valueConsumer, session ); - } - - @Override - public boolean hasPartitionedSelectionMapping() { - return getEmbeddableTypeDescriptor().hasPartitionedSelectionMapping(); - } - @Override public DomainResult createDomainResult( NavigablePath navigablePath, @@ -343,20 +296,6 @@ public class EmbeddedAttributeMapping return new SqlTuple( columnReferences, this ); } - @Override - public ModelPart findSubPart( - String name, - EntityMappingType treatTargetType) { - return getMappedType().findSubPart( name, treatTargetType ); - } - - @Override - public void visitSubParts( - Consumer consumer, - EntityMappingType treatTargetType) { - getMappedType().visitSubParts( consumer, treatTargetType ); - } - @Override public TableGroupJoin createTableGroupJoin( NavigablePath navigablePath, @@ -400,21 +339,6 @@ public class EmbeddedAttributeMapping return getAttributeName(); } - @Override - public int getNumberOfFetchables() { - return getEmbeddableTypeDescriptor().getNumberOfAttributeMappings(); - } - - @Override - public Fetchable getFetchable(int position) { - return getEmbeddableTypeDescriptor().getFetchable( position ); - } - - @Override - public int getSelectableIndex(String selectableName) { - return getEmbeddableTypeDescriptor().getSelectableIndex( selectableName ); - } - @Override public String toString() { return "EmbeddedAttributeMapping(" + navigableRole + ")@" + System.identityHashCode( this ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedCollectionPart.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedCollectionPart.java index cd55a4deaa..4308bdab97 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedCollectionPart.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedCollectionPart.java @@ -297,11 +297,6 @@ public class EmbeddedCollectionPart implements CollectionPart, EmbeddableValuedF embeddableMappingType.applySqlSelections( navigablePath, tableGroup, creationState, selectionConsumer ); } - @Override - public JavaType getJavaType() { - return getEmbeddableTypeDescriptor().getJavaType(); - } - @Override public JavaType getExpressibleJavaType() { return getJavaType(); @@ -317,32 +312,6 @@ public class EmbeddedCollectionPart implements CollectionPart, EmbeddableValuedF return collectionDescriptor.getAttributeMapping().findContainingEntityMapping(); } - @Override - public int getNumberOfFetchables() { - return getEmbeddableTypeDescriptor().getNumberOfAttributeMappings(); - } - - @Override - public Fetchable getFetchable(int position) { - return getEmbeddableTypeDescriptor().getFetchable( position ); - } - - @Override - public int forEachSelectable(int offset, SelectableConsumer consumer) { - return getEmbeddableTypeDescriptor().forEachSelectable( offset, consumer ); - } - - @Override - public int breakDownJdbcValues( - Object domainValue, - int offset, - X x, - Y y, - JdbcValueBiConsumer valueConsumer, - SharedSessionContractImplementor session) { - return getEmbeddableTypeDescriptor().breakDownJdbcValues( domainValue, offset, x, y, valueConsumer, session ); - } - @Override public FetchStyle getStyle() { return FetchStyle.JOIN; @@ -353,9 +322,4 @@ public class EmbeddedCollectionPart implements CollectionPart, EmbeddableValuedF return FetchTiming.IMMEDIATE; } - @Override - public boolean hasPartitionedSelectionMapping() { - return getEmbeddableTypeDescriptor().hasPartitionedSelectionMapping(); - } - } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedIdentifierMappingImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedIdentifierMappingImpl.java index e3f6c63f2c..61bf043384 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedIdentifierMappingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedIdentifierMappingImpl.java @@ -6,7 +6,6 @@ */ package org.hibernate.metamodel.mapping.internal; -import java.io.Serializable; import java.util.function.BiConsumer; import org.hibernate.engine.spi.SharedSessionContractImplementor; @@ -110,17 +109,6 @@ public class EmbeddedIdentifierMappingImpl return name; } - - @Override - public int getNumberOfFetchables() { - return getEmbeddableTypeDescriptor().getNumberOfAttributeMappings(); - } - - @Override - public Fetchable getFetchable(int position) { - return getEmbeddableTypeDescriptor().getFetchable( position ); - } - @Override public PropertyAccess getPropertyAccess() { return propertyAccess; @@ -131,32 +119,4 @@ public class EmbeddedIdentifierMappingImpl return name; } - @Override - public int breakDownJdbcValues( - Object domainValue, - int offset, - X x, - Y y, - JdbcValueBiConsumer valueConsumer, - SharedSessionContractImplementor session) { - return getEmbeddableTypeDescriptor().breakDownJdbcValues( domainValue, offset, x, y, valueConsumer, session ); - } - - @Override - public int forEachDisassembledJdbcValue( - Object value, - int offset, - X x, - Y y, - JdbcValuesBiConsumer valuesConsumer, - SharedSessionContractImplementor session) { - return getEmbeddableTypeDescriptor().forEachDisassembledJdbcValue( - value, - offset, - x, - y, - valuesConsumer, - session - ); - } } 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 954cf7dd78..9c440831d8 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 @@ -6,10 +6,8 @@ */ package org.hibernate.metamodel.mapping.internal; -import java.io.Serializable; import java.util.function.Consumer; -import org.hibernate.cache.MutableCacheKeyBuilder; import org.hibernate.engine.FetchStyle; import org.hibernate.engine.FetchTiming; import org.hibernate.engine.spi.EntityKey; @@ -288,49 +286,6 @@ public class IdClassEmbeddable extends AbstractEmbeddableMapping implements Iden return idMapping.findContainingEntityMapping(); } - @Override - public int breakDownJdbcValues( - Object domainValue, - int offset, - X x, - Y y, - JdbcValueBiConsumer valueConsumer, - SharedSessionContractImplementor session) { - int span = 0; - for ( int i = 0; i < attributeMappings.size(); i++ ) { - final AttributeMapping attribute = attributeMappings.get( i ); - final Object attributeValue = attribute.getValue( domainValue ); - span += attribute.breakDownJdbcValues( attributeValue, offset + span, x, y, valueConsumer, session ); - } - return span; - } - - @Override - public Object disassemble(Object value, SharedSessionContractImplementor session) { - // todo (6.0) : reduce to-one values to id here? - final Object[] result = new Object[ getNumberOfAttributeMappings() ]; - for ( int i = 0; i < result.length; i++ ) { - final AttributeMapping attributeMapping = getAttributeMapping( i ); - Object o = attributeMapping.getPropertyAccess().getGetter().get( value ); - result[i] = attributeMapping.disassemble( o, session ); - } - - return result; - } - - @Override - public void addToCacheKey(MutableCacheKeyBuilder cacheKey, Object value, SharedSessionContractImplementor session) { - if ( value == null ) { - return; - } - final Serializable[] result = new Serializable[ getNumberOfAttributeMappings() ]; - for ( int i = 0; i < result.length; i++ ) { - final AttributeMapping attributeMapping = getAttributeMapping( i ); - final Object o = attributeMapping.getPropertyAccess().getGetter().get( value ); - attributeMapping.addToCacheKey( cacheKey, o, session ); - } - } - @Override public int forEachDisassembledJdbcValue( Object value, 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 329ec9ad60..02769d7895 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 @@ -158,22 +158,6 @@ public class VirtualIdEmbeddable extends AbstractEmbeddableMapping implements Id throw new UnsupportedOperationException(); } - @Override - public int breakDownJdbcValues( - Object domainValue, - int offset, - X x, - Y y, - JdbcValueBiConsumer valueConsumer, SharedSessionContractImplementor session) { - int span = 0; - for ( int i = 0; i < attributeMappings.size(); i++ ) { - final AttributeMapping attribute = attributeMappings.get( i ); - final Object attributeValue = attribute.getValue( domainValue ); - span += attribute.breakDownJdbcValues( attributeValue, offset + span, x, y, valueConsumer, session ); - } - return span; - } - @Override public int decompose( Object domainValue, diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/TupleMappingModelExpressible.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/TupleMappingModelExpressible.java index 1f7abdc344..d6b427e2d1 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/TupleMappingModelExpressible.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/internal/TupleMappingModelExpressible.java @@ -34,6 +34,9 @@ public class TupleMappingModelExpressible implements MappingModelExpressible { @Override public Object disassemble(Object value, SharedSessionContractImplementor session) { + if ( value == null ) { + return null; + } final Object[] disassembled = new Object[components.length]; final Object[] array = (Object[]) value; for ( int i = 0; i < components.length; i++ ) { @@ -45,10 +48,15 @@ public class TupleMappingModelExpressible implements MappingModelExpressible { @Override public void addToCacheKey(MutableCacheKeyBuilder cacheKey, Object value, SharedSessionContractImplementor session) { if ( value == null ) { - return; + for ( int i = 0; i < components.length; i++ ) { + components[i].addToCacheKey( cacheKey, null, session ); + } } - for ( int i = 0; i < components.length; i++ ) { - components[i].addToCacheKey( cacheKey, value, session ); + else { + final Object[] array = (Object[]) value; + for ( int i = 0; i < components.length; i++ ) { + components[i].addToCacheKey( cacheKey, array[i], session ); + } } } @@ -60,10 +68,31 @@ public class TupleMappingModelExpressible implements MappingModelExpressible { Y y, JdbcValuesBiConsumer valuesConsumer, SharedSessionContractImplementor session) { - final Object[] values = (Object[]) value; int span = 0; - for ( int i = 0; i < components.length; i++ ) { - span += components[i].forEachDisassembledJdbcValue( values[i], span + offset, x, y, valuesConsumer, session ); + if ( value == null ) { + for ( int i = 0; i < components.length; i++ ) { + span += components[i].forEachDisassembledJdbcValue( + null, + span + offset, + x, + y, + valuesConsumer, + session + ); + } + } + else { + final Object[] values = (Object[]) value; + for ( int i = 0; i < components.length; i++ ) { + span += components[i].forEachDisassembledJdbcValue( + values[i], + span + offset, + x, + y, + valuesConsumer, + session + ); + } } return span; } @@ -76,15 +105,27 @@ public class TupleMappingModelExpressible implements MappingModelExpressible { Y y, JdbcValuesBiConsumer valuesConsumer, SharedSessionContractImplementor session) { - final Object[] values = (Object[]) value; int span = 0; - for ( int i = 0; i < components.length; i++ ) { - span += components[i].forEachDisassembledJdbcValue( - components[i].disassemble( values[i], session ), - span + offset, - x, y, valuesConsumer, - session - ); + if ( value == null ) { + for ( int i = 0; i < components.length; i++ ) { + span += components[i].forEachDisassembledJdbcValue( + components[i].disassemble( null, session ), + span + offset, + x, y, valuesConsumer, + session + ); + } + } + else { + final Object[] values = (Object[]) value; + for ( int i = 0; i < components.length; i++ ) { + span += components[i].forEachDisassembledJdbcValue( + components[i].disassemble( values[i], session ), + span + offset, + x, y, valuesConsumer, + session + ); + } } return 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 6da158e06e..f99c34cb11 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 @@ -56,6 +56,7 @@ import org.hibernate.sql.results.graph.DomainResultCreationState; import org.hibernate.sql.results.graph.Fetch; import org.hibernate.sql.results.graph.FetchOptions; import org.hibernate.sql.results.graph.FetchParent; +import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.embeddable.internal.EmbeddableResultImpl; import org.hibernate.type.descriptor.java.JavaType; @@ -67,19 +68,21 @@ public class AnonymousTupleEmbeddableValuedModelPart implements EmbeddableValued private static final FetchOptions FETCH_OPTIONS = FetchOptions.valueOf( FetchTiming.IMMEDIATE, FetchStyle.JOIN ); - private final Map modelParts; + private final Map modelPartMap; + private final ModelPart[] modelParts; private final DomainType domainType; private final String componentName; private final EmbeddableValuedModelPart existingModelPartContainer; private final int fetchableIndex; public AnonymousTupleEmbeddableValuedModelPart( - Map modelParts, + Map modelPartMap, DomainType domainType, String componentName, EmbeddableValuedModelPart existingModelPartContainer, int fetchableIndex) { - this.modelParts = modelParts; + this.modelPartMap = modelPartMap; + this.modelParts = modelPartMap.values().toArray( new ModelPart[0] ); this.domainType = domainType; this.componentName = componentName; this.existingModelPartContainer = existingModelPartContainer; @@ -88,12 +91,21 @@ public class AnonymousTupleEmbeddableValuedModelPart implements EmbeddableValued @Override public ModelPart findSubPart(String name, EntityMappingType treatTargetType) { - return modelParts.get( name ); + return modelPartMap.get( name ); + } + + @Override + public void forEachSubPart(IndexedConsumer consumer, EntityMappingType treatTarget) { + for ( int i = 0; i < modelParts.length; i++ ) { + consumer.accept( i, modelParts[i] ); + } } @Override public void visitSubParts(Consumer consumer, EntityMappingType treatTargetType) { - modelParts.values().forEach( consumer ); + for ( int i = 0; i < modelParts.length; i++ ) { + consumer.accept( modelParts[i] ); + } } @Override @@ -148,7 +160,7 @@ public class AnonymousTupleEmbeddableValuedModelPart implements EmbeddableValued @Override public int getNumberOfAttributeMappings() { - return modelParts.size(); + return modelParts.length; } @Override @@ -166,6 +178,17 @@ public class AnonymousTupleEmbeddableValuedModelPart implements EmbeddableValued throw new UnsupportedOperationException(); } + @Override + public int decompose( + Object domainValue, + int offset, + X x, + Y y, + JdbcValueBiConsumer valueConsumer, + SharedSessionContractImplementor session) { + throw new UnsupportedOperationException(); + } + @Override public Object[] getValues(Object instance) { return existingModelPartContainer.getEmbeddableTypeDescriptor() @@ -192,6 +215,11 @@ public class AnonymousTupleEmbeddableValuedModelPart implements EmbeddableValued .setValue( instance, value ); } + @Override + public int getSelectableIndex(String selectableName) { + throw new UnsupportedOperationException(); + } + @Override public SelectableMapping getSelectable(int columnIndex) { final List results = new ArrayList<>(); @@ -199,6 +227,16 @@ public class AnonymousTupleEmbeddableValuedModelPart implements EmbeddableValued return results.get( columnIndex ); } + @Override + public Fetchable getFetchable(int position) { + return (Fetchable) modelParts[position]; + } + + @Override + public JdbcMapping getJdbcMapping(int index) { + return getSelectable( index ).getJdbcMapping(); + } + @Override public List getJdbcMappings() { final List results = new ArrayList<>(); @@ -214,12 +252,22 @@ public class AnonymousTupleEmbeddableValuedModelPart implements EmbeddableValued @Override public int forEachSelectable(int offset, SelectableConsumer consumer) { int span = 0; - for ( ModelPart mapping : modelParts.values() ) { + for ( ModelPart mapping : modelParts ) { span += mapping.forEachSelectable( offset + span, consumer ); } return span; } + @Override + public void forEachInsertable(int offset, SelectableConsumer consumer) { + throw new UnsupportedOperationException(); + } + + @Override + public void forEachUpdatable(int offset, SelectableConsumer consumer) { + throw new UnsupportedOperationException(); + } + @Override public String getContainingTableExpression() { return ""; @@ -234,7 +282,7 @@ public class AnonymousTupleEmbeddableValuedModelPart implements EmbeddableValued final List columnReferences = CollectionHelper.arrayList( getJdbcTypeCount() ); final NavigablePath navigablePath = tableGroup.getNavigablePath().append( componentName ); final TableReference tableReference = tableGroup.resolveTableReference( navigablePath, getContainingTableExpression() ); - for ( ModelPart modelPart : modelParts.values() ) { + for ( ModelPart modelPart : modelParts ) { modelPart.forEachSelectable( (columnIndex, selection) -> { final Expression columnReference = sqlAstCreationState.getSqlExpressionResolver() @@ -339,7 +387,7 @@ public class AnonymousTupleEmbeddableValuedModelPart implements EmbeddableValued @Override public int getNumberOfFetchables() { - return modelParts.size(); + return modelParts.length; } @Override @@ -376,7 +424,7 @@ public class AnonymousTupleEmbeddableValuedModelPart implements EmbeddableValued NavigablePath navigablePath, TableGroup tableGroup, DomainResultCreationState creationState) { - for ( ModelPart mapping : modelParts.values() ) { + for ( ModelPart mapping : modelParts ) { mapping.applySqlSelections( navigablePath, tableGroup, creationState ); } } @@ -387,7 +435,7 @@ public class AnonymousTupleEmbeddableValuedModelPart implements EmbeddableValued TableGroup tableGroup, DomainResultCreationState creationState, BiConsumer selectionConsumer) { - for ( ModelPart mapping : modelParts.values() ) { + for ( ModelPart mapping : modelParts ) { mapping.applySqlSelections( navigablePath, tableGroup, creationState, selectionConsumer ); } } @@ -400,27 +448,33 @@ public class AnonymousTupleEmbeddableValuedModelPart implements EmbeddableValued Y y, JdbcValueBiConsumer valueConsumer, SharedSessionContractImplementor session) { - final Object[] values = (Object[]) domainValue; - assert values.length == modelParts.size(); int span = 0; - int i = 0; - for ( ModelPart mapping : modelParts.values() ) { - final Object attributeValue = values[ i ]; - span += mapping.breakDownJdbcValues( attributeValue, offset + span, x, y, valueConsumer, session ); - i++; + if ( domainValue == null ) { + for ( ModelPart mapping : modelParts ) { + span += mapping.breakDownJdbcValues( null, offset + span, x, y, valueConsumer, session ); + } + } + else { + final Object[] values = (Object[]) domainValue; + assert values.length == modelParts.length; + for ( int i = 0; i < modelParts.length; i++ ) { + final Object attributeValue = values[i]; + span += modelParts[i].breakDownJdbcValues( attributeValue, offset + span, x, y, valueConsumer, session ); + } } return span; } @Override public Object disassemble(Object value, SharedSessionContractImplementor session) { + if ( value == null ) { + return null; + } final Object[] values = (Object[]) value; - final Object[] result = new Object[ modelParts.size() ]; - int i = 0; - for ( ModelPart mapping : modelParts.values() ) { + final Object[] result = new Object[ modelParts.length ]; + for ( int i = 0; i < modelParts.length; i++ ) { Object o = values[i]; - result[i] = mapping.disassemble( o, session ); - i++; + result[i] = modelParts[i].disassemble( o, session ); } return result; @@ -428,11 +482,18 @@ public class AnonymousTupleEmbeddableValuedModelPart implements EmbeddableValued @Override public void addToCacheKey(MutableCacheKeyBuilder cacheKey, Object value, SharedSessionContractImplementor session) { - final Object[] values = (Object[]) value; - int i = 0; - for ( ModelPart mapping : modelParts.values() ) { - mapping.addToCacheKey( cacheKey, values[i], session ); - i++; + if ( value == null ) { + for ( ModelPart mapping : modelParts ) { + mapping.addToCacheKey( cacheKey, null, session ); + } + } + else { + final Object[] values = (Object[]) value; + int i = 0; + for ( ModelPart mapping : modelParts ) { + mapping.addToCacheKey( cacheKey, values[i], session ); + i++; + } } } @@ -444,12 +505,17 @@ public class AnonymousTupleEmbeddableValuedModelPart implements EmbeddableValued Y y, JdbcValuesBiConsumer valuesConsumer, SharedSessionContractImplementor session) { - final Object[] values = (Object[]) value; int span = 0; - int i = 0; - for ( ModelPart mapping : modelParts.values() ) { - span += mapping.forEachDisassembledJdbcValue( values[i], span + offset, x, y, valuesConsumer, session ); - i++; + if ( value == null ) { + for ( ModelPart mapping : modelParts ) { + span += mapping.forEachDisassembledJdbcValue( null, span + offset, x, y, valuesConsumer, session ); + } + } + else { + final Object[] values = (Object[]) value; + for ( int i = 0; i < modelParts.length; i++ ) { + span += modelParts[i].forEachDisassembledJdbcValue( values[i], span + offset, x, y, valuesConsumer, session ); + } } return span; } @@ -462,13 +528,18 @@ public class AnonymousTupleEmbeddableValuedModelPart implements EmbeddableValued Y y, JdbcValuesBiConsumer consumer, SharedSessionContractImplementor session) { - final Object[] values = (Object[]) value; int span = 0; - int i = 0; - for ( ModelPart attributeMapping : modelParts.values() ) { - final Object o = values[i]; - span += attributeMapping.forEachJdbcValue( o, span + offset, x, y, consumer, session ); - i++; + if ( value == null ) { + for ( ModelPart mapping : modelParts ) { + span += mapping.forEachJdbcValue( null, span + offset, x, y, consumer, session ); + } + } + else { + final Object[] values = (Object[]) value; + for ( int i = 0; i < modelParts.length; i++ ) { + final Object o = values[i]; + span += modelParts[i].forEachJdbcValue( o, span + offset, x, y, consumer, session ); + } } return span; } @@ -476,7 +547,7 @@ public class AnonymousTupleEmbeddableValuedModelPart implements EmbeddableValued @Override public int forEachJdbcType(int offset, IndexedConsumer action) { int span = 0; - for ( ModelPart attributeMapping : modelParts.values() ) { + for ( ModelPart attributeMapping : modelParts ) { span += attributeMapping.forEachJdbcType( span + offset, action ); } return span;