HHH-16070 Check for type parameters when setting declared identifier
This commit is contained in:
parent
3bfb2f66a1
commit
94b20bafc8
|
@ -329,7 +329,7 @@ public class ClassPropertyHolder extends AbstractPropertyHolder {
|
|||
}
|
||||
}
|
||||
|
||||
private String getTypeName(Value value) {
|
||||
static String getTypeName(Value value) {
|
||||
if ( value instanceof Component ) {
|
||||
final Component component = (Component) value;
|
||||
final String typeName = component.getTypeName();
|
||||
|
@ -341,7 +341,7 @@ public class ClassPropertyHolder extends AbstractPropertyHolder {
|
|||
return ( (SimpleValue) value ).getTypeName();
|
||||
}
|
||||
|
||||
private void setTypeName(Value value, String typeName) {
|
||||
static void setTypeName(Value value, String typeName) {
|
||||
if ( value instanceof ToOne ) {
|
||||
final ToOne toOne = (ToOne) value;
|
||||
toOne.setReferencedEntityName( typeName );
|
||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.boot.model.internal;
|
|||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -28,6 +29,7 @@ import jakarta.persistence.Version;
|
|||
import org.hibernate.AnnotationException;
|
||||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.PropertyNotFoundException;
|
||||
import org.hibernate.annotations.Any;
|
||||
import org.hibernate.annotations.AttributeBinderType;
|
||||
import org.hibernate.annotations.CompositeType;
|
||||
|
@ -317,13 +319,7 @@ public class PropertyBinder {
|
|||
inheritanceStatePerClass,
|
||||
buildingContext
|
||||
);
|
||||
if ( superclass != null ) {
|
||||
superclass.setDeclaredIdentifierProperty(property);
|
||||
}
|
||||
else {
|
||||
//we know the property is on the actual entity
|
||||
rootClass.setDeclaredIdentifierProperty( property );
|
||||
}
|
||||
setDeclaredIdentifier( rootClass, superclass, property );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -342,6 +338,65 @@ public class PropertyBinder {
|
|||
return property;
|
||||
}
|
||||
|
||||
private void setDeclaredIdentifier(RootClass rootClass, MappedSuperclass superclass, Property prop) {
|
||||
if ( superclass == null ) {
|
||||
rootClass.setDeclaredIdentifierProperty( prop );
|
||||
return;
|
||||
}
|
||||
// If the type has type parameters, we have to set the declared identifier property on the rootClass
|
||||
// to be able to retrieve it with the correct type based on type variable assignment in the subclass
|
||||
final Class<?> type = buildingContext.getBootstrapContext().getReflectionManager().toClass( declaringClass );
|
||||
if ( type.getTypeParameters().length == 0 ) {
|
||||
superclass.setDeclaredIdentifierProperty( prop );
|
||||
}
|
||||
else {
|
||||
// If the type has type parameters, we have to look up the XClass and actual property again
|
||||
// because the given XClass has a TypeEnvironment based on the type variable assignments of a subclass
|
||||
// and that might result in a wrong property type being used for a property which uses a type variable
|
||||
final XClass actualDeclaringClass = buildingContext.getBootstrapContext().getReflectionManager().toXClass( type );
|
||||
for ( XProperty declaredProperty : actualDeclaringClass.getDeclaredProperties( prop.getPropertyAccessorName() ) ) {
|
||||
if ( prop.getName().equals( declaredProperty.getName() ) ) {
|
||||
final PropertyData inferredData = new PropertyInferredData(
|
||||
actualDeclaringClass,
|
||||
declaredProperty,
|
||||
null,
|
||||
buildingContext.getBootstrapContext().getReflectionManager()
|
||||
);
|
||||
final Value originalValue = prop.getValue();
|
||||
if ( originalValue instanceof SimpleValue ) {
|
||||
// Avoid copying when the property doesn't depend on a type variable
|
||||
if ( inferredData.getTypeName().equals( ClassPropertyHolder.getTypeName( originalValue ) ) ) {
|
||||
superclass.setDeclaredIdentifierProperty( prop );
|
||||
return;
|
||||
}
|
||||
}
|
||||
// If the property depends on a type variable, we have to copy it and the Value
|
||||
final Property actualProperty = prop.copy();
|
||||
actualProperty.setReturnedClassName( inferredData.getTypeName() );
|
||||
final Value value = actualProperty.getValue().copy();
|
||||
assert !(value instanceof Collection);
|
||||
ClassPropertyHolder.setTypeName( value, inferredData.getTypeName() );
|
||||
if ( value instanceof Component ) {
|
||||
Component component = ( (Component) value );
|
||||
Iterator<Property> propertyIterator = component.getPropertyIterator();
|
||||
while ( propertyIterator.hasNext() ) {
|
||||
Property property = propertyIterator.next();
|
||||
try {
|
||||
property.getGetter( component.getComponentClass() );
|
||||
}
|
||||
catch (PropertyNotFoundException e) {
|
||||
propertyIterator.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
actualProperty.setValue( value );
|
||||
superclass.setDeclaredIdentifierProperty( actualProperty );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Component getOrCreateCompositeId(RootClass rootClass) {
|
||||
final Component id = (Component) rootClass.getIdentifier();
|
||||
if ( id == null ) {
|
||||
|
|
|
@ -583,9 +583,22 @@ public class AttributeFactory {
|
|||
|
||||
final CompositeTypeImplementor ownerComponentType = (CompositeTypeImplementor) ownerBootDescriptor.getType();
|
||||
final EmbeddableValuedModelPart ownerMappingModelDescriptor = ownerComponentType.getMappingModelPart();
|
||||
final EmbeddableRepresentationStrategy ownerRepStrategy = ownerMappingModelDescriptor
|
||||
.getEmbeddableTypeDescriptor()
|
||||
.getRepresentationStrategy();
|
||||
final EmbeddableRepresentationStrategy ownerRepStrategy;
|
||||
|
||||
if ( ownerMappingModelDescriptor == null ) {
|
||||
// When an entity uses a type variable, bound by a mapped superclass, for an embedded id,
|
||||
// we will not create a model part for the component, but we still need the representation strategy here,
|
||||
// in order to discover the property members to expose on the JPA metamodel
|
||||
ownerRepStrategy = ownerBootDescriptor.getBuildingContext()
|
||||
.getBootstrapContext()
|
||||
.getRepresentationStrategySelector()
|
||||
.resolveStrategy( ownerBootDescriptor, null, metadataContext.getRuntimeModelCreationContext() );
|
||||
}
|
||||
else {
|
||||
ownerRepStrategy = ownerMappingModelDescriptor
|
||||
.getEmbeddableTypeDescriptor()
|
||||
.getRepresentationStrategy();
|
||||
}
|
||||
|
||||
if ( ownerRepStrategy.getMode() == RepresentationMode.MAP ) {
|
||||
return new MapMember(
|
||||
|
|
|
@ -24,6 +24,7 @@ import org.hibernate.internal.HEMLogging;
|
|||
import org.hibernate.internal.util.ReflectHelper;
|
||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.mapping.Component;
|
||||
import org.hibernate.mapping.KeyValue;
|
||||
import org.hibernate.mapping.MappedSuperclass;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
|
@ -428,6 +429,12 @@ public class MetadataContext {
|
|||
//noinspection unchecked rawtypes
|
||||
( ( AttributeContainer) identifiableType ).getInFlightAccess().applyIdAttribute( idAttribute );
|
||||
}
|
||||
else if ( persistentClass.getIdentifier() instanceof Component
|
||||
&& persistentClass.getIdentifierProperty() != getSuperclassIdentifier( persistentClass ) ) {
|
||||
// If the identifier is a generic component, we have to call buildIdAttribute anyway,
|
||||
// as this will create and register the EmbeddableType for the subtype
|
||||
attributeFactory.buildIdAttribute( identifiableType, persistentClass.getIdentifierProperty() );
|
||||
}
|
||||
}
|
||||
else {
|
||||
// we have a non-aggregated composite-id
|
||||
|
@ -476,6 +483,34 @@ public class MetadataContext {
|
|||
}
|
||||
}
|
||||
|
||||
private Property getSuperclassIdentifier(PersistentClass persistentClass) {
|
||||
final Property declaredIdentifierProperty = persistentClass.getDeclaredIdentifierProperty();
|
||||
if ( declaredIdentifierProperty != null ) {
|
||||
return declaredIdentifierProperty;
|
||||
}
|
||||
if ( persistentClass.getSuperMappedSuperclass() != null ) {
|
||||
return getSuperclassIdentifier( persistentClass.getSuperMappedSuperclass() );
|
||||
}
|
||||
else if ( persistentClass.getSuperclass() != null ) {
|
||||
return getSuperclassIdentifier( persistentClass.getSuperclass() );
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Property getSuperclassIdentifier(MappedSuperclass persistentClass) {
|
||||
final Property declaredIdentifierProperty = persistentClass.getDeclaredIdentifierProperty();
|
||||
if ( declaredIdentifierProperty != null ) {
|
||||
return declaredIdentifierProperty;
|
||||
}
|
||||
if ( persistentClass.getSuperMappedSuperclass() != null ) {
|
||||
return getSuperclassIdentifier( persistentClass.getSuperMappedSuperclass() );
|
||||
}
|
||||
else if ( persistentClass.getSuperPersistentClass() != null ) {
|
||||
return getSuperclassIdentifier( persistentClass.getSuperPersistentClass() );
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private EmbeddableTypeImpl<?> applyIdClassMetadata(Component idClassComponent) {
|
||||
final JavaTypeRegistry registry = getTypeConfiguration()
|
||||
.getJavaTypeRegistry();
|
||||
|
|
Loading…
Reference in New Issue