HHH-18062 Fix id-class record instantiation and mapper component

This commit is contained in:
Marco Belladelli 2024-05-21 16:32:34 +02:00 committed by Steve Ebersole
parent 996783c380
commit 677c8b6529
4 changed files with 73 additions and 29 deletions

View File

@ -495,7 +495,7 @@ public class EntityBinder {
else { else {
final boolean ignoreIdAnnotations = isIgnoreIdAnnotations(); final boolean ignoreIdAnnotations = isIgnoreIdAnnotations();
setIgnoreIdAnnotations( true ); setIgnoreIdAnnotations( true );
bindIdClass( final Component idClassComponent = bindIdClass(
inferredData, inferredData,
baseInferredData, baseInferredData,
propertyHolder, propertyHolder,
@ -514,6 +514,9 @@ public class EntityBinder {
propertyAccessor, propertyAccessor,
true true
); );
if ( idClassComponent.isSimpleRecord() ) {
mapper.setSimpleRecord( true );
}
setIgnoreIdAnnotations( ignoreIdAnnotations ); setIgnoreIdAnnotations( ignoreIdAnnotations );
for ( Property property : mapper.getProperties() ) { for ( Property property : mapper.getProperties() ) {
idPropertiesIfIdClass.add( property.getName() ); idPropertiesIfIdClass.add( property.getName() );
@ -656,7 +659,7 @@ public class EntityBinder {
} }
} }
private void bindIdClass( private Component bindIdClass(
PropertyData inferredData, PropertyData inferredData,
PropertyData baseInferredData, PropertyData baseInferredData,
PropertyHolder propertyHolder, PropertyHolder propertyHolder,
@ -707,6 +710,8 @@ public class EntityBinder {
rootClass.setEmbeddedIdentifier( inferredData.getPropertyClass() == null ); rootClass.setEmbeddedIdentifier( inferredData.getPropertyClass() == null );
propertyHolder.setInIdClass( null ); propertyHolder.setInIdClass( null );
return id;
} }
private static void handleIdGenerator(PropertyData inferredData, MetadataBuildingContext buildingContext, Component id) { private static void handleIdGenerator(PropertyData inferredData, MetadataBuildingContext buildingContext, Component id) {

View File

@ -108,6 +108,7 @@ public class Component extends SimpleValue implements MetaAttributable, Sortable
private QualifiedName structName; private QualifiedName structName;
private String[] structColumnNames; private String[] structColumnNames;
private transient Class<?> componentClass; private transient Class<?> componentClass;
private transient Boolean simpleRecord;
private transient Generator builtIdentifierGenerator; private transient Generator builtIdentifierGenerator;
@ -377,6 +378,7 @@ public class Component extends SimpleValue implements MetaAttributable, Sortable
public void setComponentClassName(String componentClass) { public void setComponentClassName(String componentClass) {
this.componentClassName = componentClass; this.componentClassName = componentClass;
this.componentClass = null; this.componentClass = null;
this.simpleRecord = null;
} }
public void setEmbedded(boolean embedded) { public void setEmbedded(boolean embedded) {
@ -899,26 +901,33 @@ public class Component extends SimpleValue implements MetaAttributable, Sortable
return this.originalPropertyOrder = originalPropertyOrder; return this.originalPropertyOrder = originalPropertyOrder;
} }
private boolean isSimpleRecord() { public void setSimpleRecord(boolean simpleRecord) {
// A simple record is given, when the properties match the order of the record component names this.simpleRecord = simpleRecord;
final Class<?> componentClass = resolveComponentClass(); }
if ( customInstantiator != null ) {
return false;
}
if ( componentClass == null || !ReflectHelper.isRecord( componentClass ) ) {
return false;
}
final String[] recordComponentNames = ReflectHelper.getRecordComponentNames( componentClass );
if ( recordComponentNames.length != properties.size() ) {
return false;
}
for ( int i = 0; i < recordComponentNames.length; i++ ) {
if ( !recordComponentNames[i].equals( properties.get( i ).getName() ) ) {
return false;
}
}
return true; public boolean isSimpleRecord() {
Boolean simple = simpleRecord;
if ( simple == null ) {
// A simple record is given, when the properties match the order of the record component names
final Class<?> componentClass = resolveComponentClass();
if ( customInstantiator != null ) {
return simpleRecord = false;
}
if ( componentClass == null || !ReflectHelper.isRecord( componentClass ) ) {
return simpleRecord = false;
}
final String[] recordComponentNames = ReflectHelper.getRecordComponentNames( componentClass );
if ( recordComponentNames.length != properties.size() ) {
return simpleRecord = false;
}
for ( int i = 0; i < recordComponentNames.length; i++ ) {
if ( !recordComponentNames[i].equals( properties.get( i ).getName() ) ) {
return simpleRecord = false;
}
}
simple = simpleRecord = true;
}
return simple;
} }
public Class<? extends EmbeddableInstantiator> getCustomInstantiator() { public Class<? extends EmbeddableInstantiator> getCustomInstantiator() {

View File

@ -74,7 +74,11 @@ public class IdClassEmbeddable extends AbstractEmbeddableMapping implements Iden
.getJavaTypeRegistry() .getJavaTypeRegistry()
.resolveManagedTypeDescriptor( idClassSource.getComponentClass() ); .resolveManagedTypeDescriptor( idClassSource.getComponentClass() );
this.representationStrategy = new IdClassRepresentationStrategy( this ); this.representationStrategy = new IdClassRepresentationStrategy(
this,
idClassSource.sortProperties() == null,
idClassSource::getPropertyNames
);
final PropertyAccess propertyAccess = PropertyAccessStrategyMapImpl.INSTANCE.buildPropertyAccess( final PropertyAccess propertyAccess = PropertyAccessStrategyMapImpl.INSTANCE.buildPropertyAccess(
null, null,
@ -101,7 +105,7 @@ public class IdClassEmbeddable extends AbstractEmbeddableMapping implements Iden
propertyAccess propertyAccess
); );
final CompositeType idClassType = (CompositeType) idClassSource.getType(); final CompositeType idClassType = idClassSource.getType();
( (CompositeTypeImplementor) idClassType ).injectMappingModelPart( embedded, creationProcess ); ( (CompositeTypeImplementor) idClassType ).injectMappingModelPart( embedded, creationProcess );
creationProcess.registerInitializationCallback( creationProcess.registerInitializationCallback(
@ -127,10 +131,16 @@ public class IdClassEmbeddable extends AbstractEmbeddableMapping implements Iden
super( new MutableAttributeMappingList( inverseMappingType.attributeMappings.size() ) ); super( new MutableAttributeMappingList( inverseMappingType.attributeMappings.size() ) );
this.navigableRole = inverseMappingType.getNavigableRole(); this.navigableRole = inverseMappingType.getNavigableRole();
this.idMapping = (NonAggregatedIdentifierMapping) valueMapping;; this.idMapping = (NonAggregatedIdentifierMapping) valueMapping;
this.virtualIdEmbeddable = (VirtualIdEmbeddable) valueMapping.getEmbeddableTypeDescriptor(); this.virtualIdEmbeddable = (VirtualIdEmbeddable) valueMapping.getEmbeddableTypeDescriptor();
this.javaType = inverseMappingType.javaType; this.javaType = inverseMappingType.javaType;
this.representationStrategy = new IdClassRepresentationStrategy( this ); this.representationStrategy = new IdClassRepresentationStrategy( this, false, () -> {
final String[] attributeNames = new String[inverseMappingType.getNumberOfAttributeMappings()];
for ( int i = 0; i < attributeNames.length; i++ ) {
attributeNames[i] = inverseMappingType.getAttributeMapping( i ).getAttributeName();
}
return attributeNames;
} );
this.embedded = valueMapping; this.embedded = valueMapping;
this.selectableMappings = selectableMappings; this.selectableMappings = selectableMappings;
creationProcess.registerInitializationCallback( creationProcess.registerInitializationCallback(

View File

@ -7,12 +7,14 @@
package org.hibernate.metamodel.mapping.internal; package org.hibernate.metamodel.mapping.internal;
import java.util.Locale; import java.util.Locale;
import java.util.function.Supplier;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.bytecode.spi.ReflectionOptimizer; import org.hibernate.bytecode.spi.ReflectionOptimizer;
import org.hibernate.mapping.Property; import org.hibernate.mapping.Property;
import org.hibernate.metamodel.RepresentationMode; import org.hibernate.metamodel.RepresentationMode;
import org.hibernate.metamodel.internal.EmbeddableInstantiatorPojoStandard; import org.hibernate.metamodel.internal.EmbeddableInstantiatorPojoStandard;
import org.hibernate.metamodel.internal.EmbeddableInstantiatorRecordIndirecting;
import org.hibernate.metamodel.internal.EmbeddableInstantiatorRecordStandard; import org.hibernate.metamodel.internal.EmbeddableInstantiatorRecordStandard;
import org.hibernate.metamodel.spi.EmbeddableInstantiator; import org.hibernate.metamodel.spi.EmbeddableInstantiator;
import org.hibernate.metamodel.spi.EmbeddableRepresentationStrategy; import org.hibernate.metamodel.spi.EmbeddableRepresentationStrategy;
@ -29,11 +31,29 @@ public class IdClassRepresentationStrategy implements EmbeddableRepresentationSt
private final JavaType<?> idClassType; private final JavaType<?> idClassType;
private final EmbeddableInstantiator instantiator; private final EmbeddableInstantiator instantiator;
public IdClassRepresentationStrategy(IdClassEmbeddable idClassEmbeddable) { public IdClassRepresentationStrategy(
IdClassEmbeddable idClassEmbeddable,
boolean simplePropertyOrder,
Supplier<String[]> attributeNamesAccess) {
this.idClassType = idClassEmbeddable.getMappedJavaType(); this.idClassType = idClassEmbeddable.getMappedJavaType();
this.instantiator = isRecord( idClassType.getJavaTypeClass() ) ? final Class<?> javaTypeClass = idClassType.getJavaTypeClass();
new EmbeddableInstantiatorRecordStandard( idClassType.getJavaTypeClass() ) : if ( isRecord( javaTypeClass ) ) {
new EmbeddableInstantiatorPojoStandard( idClassType.getJavaTypeClass(), () -> idClassEmbeddable ); if ( simplePropertyOrder ) {
this.instantiator = new EmbeddableInstantiatorRecordStandard( javaTypeClass );
}
else {
this.instantiator = EmbeddableInstantiatorRecordIndirecting.of(
javaTypeClass,
attributeNamesAccess.get()
);
}
}
else {
this.instantiator = new EmbeddableInstantiatorPojoStandard(
idClassType.getJavaTypeClass(),
() -> idClassEmbeddable
);
}
} }
@Override @Override