HHH-16015 Merge operation throws a NPE: Cannot invoke org.hibernate.property.access.spi.Setter.set(Object, Object) when using CompositeUserType

This commit is contained in:
Andrea Boriero 2023-03-06 12:41:03 +01:00 committed by Christian Beikov
parent 7aea8723f2
commit bc582290a0
3 changed files with 56 additions and 39 deletions

View File

@ -69,15 +69,13 @@ public class ManagedTypeRepresentationResolverStandard implements ManagedTypeRep
Supplier<EmbeddableMappingType> runtimeDescriptorAccess, Supplier<EmbeddableMappingType> runtimeDescriptorAccess,
RuntimeModelCreationContext creationContext) { RuntimeModelCreationContext creationContext) {
// RepresentationMode representation = bootDescriptor.getExplicitRepresentationMode(); // RepresentationMode representation = bootDescriptor.getExplicitRepresentationMode();
RepresentationMode representation = null; final RepresentationMode representation;
if ( representation == null ) {
if ( bootDescriptor.getComponentClassName() == null ) { if ( bootDescriptor.getComponentClassName() == null ) {
representation = RepresentationMode.MAP; representation = RepresentationMode.MAP;
} }
else { else {
representation = RepresentationMode.POJO; representation = RepresentationMode.POJO;
} }
}
final CompositeUserType<?> compositeUserType; final CompositeUserType<?> compositeUserType;
if ( bootDescriptor.getTypeName() != null ) { if ( bootDescriptor.getTypeName() != null ) {

View File

@ -837,4 +837,8 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
} }
return mappingModelPart; return mappingModelPart;
} }
public boolean isCompositeUserType() {
return compositeUserType != null;
}
} }

View File

@ -11,6 +11,7 @@ import java.util.Map;
import org.hibernate.Internal; import org.hibernate.Internal;
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer; import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.metamodel.spi.EmbeddableInstantiator;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.property.access.internal.PropertyAccessStrategyBackRefImpl; import org.hibernate.property.access.internal.PropertyAccessStrategyBackRefImpl;
@ -182,22 +183,25 @@ public class TypeHelper {
final Object owner, final Object owner,
final Map<Object, Object> copyCache, final Map<Object, Object> copyCache,
final ForeignKeyDirection foreignKeyDirection) { final ForeignKeyDirection foreignKeyDirection) {
Object[] copied = new Object[original.length]; final Object[] copied = new Object[original.length];
for ( int i = 0; i < types.length; i++ ) { for ( int i = 0; i < types.length; i++ ) {
if ( original[i] == LazyPropertyInitializer.UNFETCHED_PROPERTY final Object currentOriginal = original[i];
|| original[i] == PropertyAccessStrategyBackRefImpl.UNKNOWN ) { if ( currentOriginal == LazyPropertyInitializer.UNFETCHED_PROPERTY
|| currentOriginal == PropertyAccessStrategyBackRefImpl.UNKNOWN ) {
copied[i] = target[i]; copied[i] = target[i];
} }
else if ( types[i].isComponentType() ) { else {
final Type type = types[i];
if ( type.isComponentType() ) {
final CompositeType compositeType = (CompositeType) type;
// need to extract the component values and check for subtype replacements... // need to extract the component values and check for subtype replacements...
CompositeType componentType = ( CompositeType ) types[i]; final Type[] subtypes = compositeType.getSubtypes();
Type[] subtypes = componentType.getSubtypes(); final Object[] origComponentValues = currentOriginal == null
Object[] origComponentValues = original[i] == null
? new Object[subtypes.length] ? new Object[subtypes.length]
: componentType.getPropertyValues( original[i], session ); : compositeType.getPropertyValues( currentOriginal, session );
Object[] targetComponentValues = target[i] == null final Object[] targetComponentValues = target[i] == null
? new Object[subtypes.length] ? new Object[subtypes.length]
: componentType.getPropertyValues( target[i], session ); : compositeType.getPropertyValues( target[i], session );
final Object[] objects = replaceAssociations( final Object[] objects = replaceAssociations(
origComponentValues, origComponentValues,
targetComponentValues, targetComponentValues,
@ -207,16 +211,27 @@ public class TypeHelper {
copyCache, copyCache,
foreignKeyDirection foreignKeyDirection
); );
if ( componentType.isMutable() && target[i] != null && objects != null ) { if ( target[i] != null && compositeType instanceof ComponentType ) {
componentType.setPropertyValues( target[i], objects ); 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]; copied[i] = target[i];
} }
else if ( !types[i].isAssociationType() ) { else if ( !type.isAssociationType() ) {
copied[i] = target[i]; copied[i] = target[i];
} }
else { else {
copied[i] = types[i].replace( original[i], target[i], session, owner, copyCache, foreignKeyDirection ); copied[i] = types[i].replace( currentOriginal, target[i], session, owner, copyCache, foreignKeyDirection );
}
} }
} }
return copied; return copied;