From bc582290a064ff4b4d3ae6ffe25efdcb6fb31f3f Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Mon, 6 Mar 2023 12:41:03 +0100 Subject: [PATCH] HHH-16015 Merge operation throws a NPE: Cannot invoke org.hibernate.property.access.spi.Setter.set(Object, Object) when using CompositeUserType --- ...gedTypeRepresentationResolverStandard.java | 14 ++-- .../org/hibernate/type/ComponentType.java | 4 + .../java/org/hibernate/type/TypeHelper.java | 77 +++++++++++-------- 3 files changed, 56 insertions(+), 39 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/ManagedTypeRepresentationResolverStandard.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/ManagedTypeRepresentationResolverStandard.java index a43cf1b666..975950e5bf 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/ManagedTypeRepresentationResolverStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/ManagedTypeRepresentationResolverStandard.java @@ -69,14 +69,12 @@ public class ManagedTypeRepresentationResolverStandard implements ManagedTypeRep Supplier runtimeDescriptorAccess, RuntimeModelCreationContext creationContext) { // RepresentationMode representation = bootDescriptor.getExplicitRepresentationMode(); - RepresentationMode representation = null; - if ( representation == null ) { - if ( bootDescriptor.getComponentClassName() == null ) { - representation = RepresentationMode.MAP; - } - else { - representation = RepresentationMode.POJO; - } + final RepresentationMode representation; + if ( bootDescriptor.getComponentClassName() == null ) { + representation = RepresentationMode.MAP; + } + else { + representation = RepresentationMode.POJO; } final CompositeUserType compositeUserType; 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 9d733d3768..02c49573d9 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/ComponentType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/ComponentType.java @@ -837,4 +837,8 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen } return mappingModelPart; } + + public boolean isCompositeUserType() { + return compositeUserType != null; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/type/TypeHelper.java b/hibernate-core/src/main/java/org/hibernate/type/TypeHelper.java index a3b9e24856..fa6557bfba 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/TypeHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/type/TypeHelper.java @@ -11,6 +11,7 @@ import java.util.Map; import org.hibernate.Internal; import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer; import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.metamodel.spi.EmbeddableInstantiator; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.property.access.internal.PropertyAccessStrategyBackRefImpl; @@ -182,41 +183,55 @@ public class TypeHelper { final Object owner, final Map copyCache, final ForeignKeyDirection foreignKeyDirection) { - Object[] copied = new Object[original.length]; + final Object[] copied = new Object[original.length]; for ( int i = 0; i < types.length; i++ ) { - if ( original[i] == LazyPropertyInitializer.UNFETCHED_PROPERTY - || original[i] == PropertyAccessStrategyBackRefImpl.UNKNOWN ) { - copied[i] = target[i]; - } - else if ( types[i].isComponentType() ) { - // need to extract the component values and check for subtype replacements... - CompositeType componentType = ( CompositeType ) types[i]; - Type[] subtypes = componentType.getSubtypes(); - Object[] origComponentValues = original[i] == null - ? new Object[subtypes.length] - : componentType.getPropertyValues( original[i], session ); - Object[] targetComponentValues = target[i] == null - ? new Object[subtypes.length] - : componentType.getPropertyValues( target[i], session ); - final Object[] objects = replaceAssociations( - origComponentValues, - targetComponentValues, - subtypes, - session, - null, - copyCache, - foreignKeyDirection - ); - if ( componentType.isMutable() && target[i] != null && objects != null ) { - componentType.setPropertyValues( target[i], objects ); - } - copied[i] = target[i]; - } - else if ( !types[i].isAssociationType() ) { + final Object currentOriginal = original[i]; + if ( currentOriginal == LazyPropertyInitializer.UNFETCHED_PROPERTY + || currentOriginal == PropertyAccessStrategyBackRefImpl.UNKNOWN ) { copied[i] = target[i]; } else { - copied[i] = types[i].replace( original[i], target[i], session, owner, copyCache, foreignKeyDirection ); + final Type type = types[i]; + if ( type.isComponentType() ) { + final CompositeType compositeType = (CompositeType) type; + // need to extract the component values and check for subtype replacements... + final Type[] subtypes = compositeType.getSubtypes(); + final Object[] origComponentValues = currentOriginal == null + ? new Object[subtypes.length] + : compositeType.getPropertyValues( currentOriginal, session ); + final Object[] targetComponentValues = target[i] == null + ? new Object[subtypes.length] + : compositeType.getPropertyValues( target[i], session ); + final Object[] objects = replaceAssociations( + origComponentValues, + targetComponentValues, + subtypes, + session, + null, + copyCache, + foreignKeyDirection + ); + if ( target[i] != null && compositeType instanceof ComponentType ) { + final ComponentType componentType = (ComponentType) compositeType; + if ( componentType.isCompositeUserType() ) { + final EmbeddableInstantiator instantiator = ( (ComponentType) compositeType ).getMappingModelPart() + .getEmbeddableTypeDescriptor() + .getRepresentationStrategy() + .getInstantiator(); + target[i] = instantiator.instantiate( () -> objects, session.getSessionFactory() ); + } + else { + compositeType.setPropertyValues( target[i], objects ); + } + } + copied[i] = target[i]; + } + else if ( !type.isAssociationType() ) { + copied[i] = target[i]; + } + else { + copied[i] = types[i].replace( currentOriginal, target[i], session, owner, copyCache, foreignKeyDirection ); + } } } return copied;