HHH-15493 Allow Java records as @IdClass

This commit is contained in:
Marco Belladelli 2024-02-19 13:45:54 +01:00 committed by Christian Beikov
parent efb02b72e5
commit 1196f72798
3 changed files with 42 additions and 12 deletions

View File

@ -441,8 +441,7 @@ private static List<PropertyData> collectClassElements(
addElementsOfClass( classElements, container, context); addElementsOfClass( classElements, container, context);
//add elements of the embeddable's mapped superclasses //add elements of the embeddable's mapped superclasses
XClass superClass = annotatedClass.getSuperclass(); XClass superClass = annotatedClass.getSuperclass();
while ( superClass != null && ( superClass.isAnnotationPresent( MappedSuperclass.class ) while ( isValidSuperclass( superClass, isIdClass ) ) {
|| ( isIdClass && !Object.class.getName().equals( superClass.getName() ) ) ) ) {
//FIXME: proper support of type variables incl var resolved at upper levels //FIXME: proper support of type variables incl var resolved at upper levels
final PropertyContainer superContainer = final PropertyContainer superContainer =
new PropertyContainer( superClass, annotatedClass, propertyAccessor ); new PropertyContainer( superClass, annotatedClass, propertyAccessor );
@ -452,6 +451,17 @@ private static List<PropertyData> collectClassElements(
return classElements; return classElements;
} }
private static boolean isValidSuperclass(XClass superClass, boolean isIdClass) {
if ( superClass == null ) {
return false;
}
return superClass.isAnnotationPresent( MappedSuperclass.class )
|| ( isIdClass
&& !superClass.getName().equals( Object.class.getName() )
&& !superClass.getName().equals( "java.lang.Record" ) );
}
private static List<PropertyData> collectBaseClassElements( private static List<PropertyData> collectBaseClassElements(
PropertyData baseInferredData, PropertyData baseInferredData,
AccessType propertyAccessor, AccessType propertyAccessor,

View File

@ -6,16 +6,22 @@
*/ */
package org.hibernate.metamodel.mapping.internal; package org.hibernate.metamodel.mapping.internal;
import java.util.Locale;
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.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;
import org.hibernate.property.access.internal.PropertyAccessStrategyMixedImpl;
import org.hibernate.property.access.spi.PropertyAccess; import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.property.access.spi.PropertyAccessStrategy;
import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.JavaType;
import static org.hibernate.internal.util.ReflectHelper.isRecord;
/** /**
* EmbeddableRepresentationStrategy for an IdClass mapping * EmbeddableRepresentationStrategy for an IdClass mapping
*/ */
@ -25,7 +31,9 @@ public class IdClassRepresentationStrategy implements EmbeddableRepresentationSt
public IdClassRepresentationStrategy(IdClassEmbeddable idClassEmbeddable) { public IdClassRepresentationStrategy(IdClassEmbeddable idClassEmbeddable) {
this.idClassType = idClassEmbeddable.getMappedJavaType(); this.idClassType = idClassEmbeddable.getMappedJavaType();
this.instantiator = new EmbeddableInstantiatorPojoStandard( idClassType, () -> idClassEmbeddable ); this.instantiator = isRecord( idClassType.getJavaTypeClass() ) ?
new EmbeddableInstantiatorRecordStandard( idClassType.getJavaTypeClass() ) :
new EmbeddableInstantiatorPojoStandard( idClassType, () -> idClassEmbeddable );
} }
@Override @Override
@ -50,9 +58,23 @@ public JavaType<?> getMappedJavaType() {
@Override @Override
public PropertyAccess resolvePropertyAccess(Property bootAttributeDescriptor) { public PropertyAccess resolvePropertyAccess(Property bootAttributeDescriptor) {
return PropertyAccessStrategyMixedImpl.INSTANCE.buildPropertyAccess( final PropertyAccessStrategy strategy = bootAttributeDescriptor.getPropertyAccessStrategy( idClassType.getJavaTypeClass() );
if ( strategy == null ) {
throw new HibernateException(
String.format(
Locale.ROOT,
"Could not resolve PropertyAccess for attribute `%s#%s`",
idClassType.getTypeName(),
bootAttributeDescriptor.getName()
)
);
}
return strategy.buildPropertyAccess(
idClassType.getJavaTypeClass(), idClassType.getJavaTypeClass(),
bootAttributeDescriptor.getName(), bootAttributeDescriptor.getName(),
true ); false
);
} }
} }

View File

@ -231,10 +231,6 @@ public Object getIdentifier(Object entity) {
if ( lazyInitializer != null ) { if ( lazyInitializer != null ) {
return lazyInitializer.getIdentifier(); return lazyInitializer.getIdentifier();
} }
final Object id = identifierValueMapper.getRepresentationStrategy().getInstantiator().instantiate(
null,
sessionFactory
);
final EmbeddableMappingType embeddableTypeDescriptor = getEmbeddableTypeDescriptor(); final EmbeddableMappingType embeddableTypeDescriptor = getEmbeddableTypeDescriptor();
final Object[] propertyValues = new Object[embeddableTypeDescriptor.getNumberOfAttributeMappings()]; final Object[] propertyValues = new Object[embeddableTypeDescriptor.getNumberOfAttributeMappings()];
for ( int i = 0; i < propertyValues.length; i++ ) { for ( int i = 0; i < propertyValues.length; i++ ) {
@ -268,8 +264,10 @@ else if ( attributeMapping instanceof ToOneAttributeMapping
propertyValues[i] = o; propertyValues[i] = o;
} }
} }
identifierValueMapper.setValues( id, propertyValues ); return identifierValueMapper.getRepresentationStrategy().getInstantiator().instantiate(
return id; () -> propertyValues,
sessionFactory
);
} }
else { else {
return entity; return entity;