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
parent 24e015237c
commit 6bf3f15af3
4 changed files with 73 additions and 29 deletions

View File

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

View File

@ -89,6 +89,7 @@ public class Component extends SimpleValue implements MetaAttributable, Sortable
private AggregateColumn parentAggregateColumn;
private String structName;
private String[] structColumnNames;
private transient Boolean simpleRecord;
// lazily computed based on 'properties' field: invalidate by setting to null when properties are modified
private transient List<Selectable> cachedSelectables;
// lazily computed based on 'properties' field: invalidate by setting to null when properties are modified
@ -315,6 +316,7 @@ public class Component extends SimpleValue implements MetaAttributable, Sortable
public void setComponentClassName(String componentClass) {
this.componentClassName = componentClass;
this.simpleRecord = null;
}
public void setEmbedded(boolean embedded) {
@ -777,26 +779,33 @@ public class Component extends SimpleValue implements MetaAttributable, Sortable
return this.originalPropertyOrder = originalPropertyOrder;
}
private boolean isSimpleRecord() {
// A simple record is given, when the properties match the order of the record component names
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;
}
}
public void setSimpleRecord(boolean simpleRecord) {
this.simpleRecord = simpleRecord;
}
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() {

View File

@ -74,7 +74,11 @@ public class IdClassEmbeddable extends AbstractEmbeddableMapping implements Iden
.getJavaTypeRegistry()
.resolveManagedTypeDescriptor( idClassSource.getComponentClass() );
this.representationStrategy = new IdClassRepresentationStrategy( this );
this.representationStrategy = new IdClassRepresentationStrategy(
this,
idClassSource.sortProperties() == null,
idClassSource::getPropertyNames
);
final PropertyAccess propertyAccess = PropertyAccessStrategyMapImpl.INSTANCE.buildPropertyAccess(
null,
@ -101,7 +105,7 @@ public class IdClassEmbeddable extends AbstractEmbeddableMapping implements Iden
propertyAccess
);
final CompositeType idClassType = (CompositeType) idClassSource.getType();
final CompositeType idClassType = idClassSource.getType();
( (CompositeTypeImplementor) idClassType ).injectMappingModelPart( embedded, creationProcess );
creationProcess.registerInitializationCallback(
@ -127,10 +131,16 @@ public class IdClassEmbeddable extends AbstractEmbeddableMapping implements Iden
super( new MutableAttributeMappingList( inverseMappingType.attributeMappings.size() ) );
this.navigableRole = inverseMappingType.getNavigableRole();
this.idMapping = (NonAggregatedIdentifierMapping) valueMapping;;
this.idMapping = (NonAggregatedIdentifierMapping) valueMapping;
this.virtualIdEmbeddable = (VirtualIdEmbeddable) valueMapping.getEmbeddableTypeDescriptor();
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.selectableMappings = selectableMappings;
creationProcess.registerInitializationCallback(

View File

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