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 ) {
|
if ( value instanceof Component ) {
|
||||||
final Component component = (Component) value;
|
final Component component = (Component) value;
|
||||||
final String typeName = component.getTypeName();
|
final String typeName = component.getTypeName();
|
||||||
|
@ -341,7 +341,7 @@ public class ClassPropertyHolder extends AbstractPropertyHolder {
|
||||||
return ( (SimpleValue) value ).getTypeName();
|
return ( (SimpleValue) value ).getTypeName();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setTypeName(Value value, String typeName) {
|
static void setTypeName(Value value, String typeName) {
|
||||||
if ( value instanceof ToOne ) {
|
if ( value instanceof ToOne ) {
|
||||||
final ToOne toOne = (ToOne) value;
|
final ToOne toOne = (ToOne) value;
|
||||||
toOne.setReferencedEntityName( typeName );
|
toOne.setReferencedEntityName( typeName );
|
||||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.boot.model.internal;
|
||||||
|
|
||||||
import java.lang.annotation.Annotation;
|
import java.lang.annotation.Annotation;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -28,6 +29,7 @@ import jakarta.persistence.Version;
|
||||||
import org.hibernate.AnnotationException;
|
import org.hibernate.AnnotationException;
|
||||||
import org.hibernate.AssertionFailure;
|
import org.hibernate.AssertionFailure;
|
||||||
import org.hibernate.MappingException;
|
import org.hibernate.MappingException;
|
||||||
|
import org.hibernate.PropertyNotFoundException;
|
||||||
import org.hibernate.annotations.Any;
|
import org.hibernate.annotations.Any;
|
||||||
import org.hibernate.annotations.AttributeBinderType;
|
import org.hibernate.annotations.AttributeBinderType;
|
||||||
import org.hibernate.annotations.CompositeType;
|
import org.hibernate.annotations.CompositeType;
|
||||||
|
@ -317,13 +319,7 @@ public class PropertyBinder {
|
||||||
inheritanceStatePerClass,
|
inheritanceStatePerClass,
|
||||||
buildingContext
|
buildingContext
|
||||||
);
|
);
|
||||||
if ( superclass != null ) {
|
setDeclaredIdentifier( rootClass, superclass, property );
|
||||||
superclass.setDeclaredIdentifierProperty(property);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
//we know the property is on the actual entity
|
|
||||||
rootClass.setDeclaredIdentifierProperty( property );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -342,6 +338,65 @@ public class PropertyBinder {
|
||||||
return property;
|
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) {
|
private Component getOrCreateCompositeId(RootClass rootClass) {
|
||||||
final Component id = (Component) rootClass.getIdentifier();
|
final Component id = (Component) rootClass.getIdentifier();
|
||||||
if ( id == null ) {
|
if ( id == null ) {
|
||||||
|
|
|
@ -583,9 +583,22 @@ public class AttributeFactory {
|
||||||
|
|
||||||
final CompositeTypeImplementor ownerComponentType = (CompositeTypeImplementor) ownerBootDescriptor.getType();
|
final CompositeTypeImplementor ownerComponentType = (CompositeTypeImplementor) ownerBootDescriptor.getType();
|
||||||
final EmbeddableValuedModelPart ownerMappingModelDescriptor = ownerComponentType.getMappingModelPart();
|
final EmbeddableValuedModelPart ownerMappingModelDescriptor = ownerComponentType.getMappingModelPart();
|
||||||
final EmbeddableRepresentationStrategy ownerRepStrategy = ownerMappingModelDescriptor
|
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()
|
.getEmbeddableTypeDescriptor()
|
||||||
.getRepresentationStrategy();
|
.getRepresentationStrategy();
|
||||||
|
}
|
||||||
|
|
||||||
if ( ownerRepStrategy.getMode() == RepresentationMode.MAP ) {
|
if ( ownerRepStrategy.getMode() == RepresentationMode.MAP ) {
|
||||||
return new MapMember(
|
return new MapMember(
|
||||||
|
|
|
@ -24,6 +24,7 @@ import org.hibernate.internal.HEMLogging;
|
||||||
import org.hibernate.internal.util.ReflectHelper;
|
import org.hibernate.internal.util.ReflectHelper;
|
||||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||||
import org.hibernate.mapping.Component;
|
import org.hibernate.mapping.Component;
|
||||||
|
import org.hibernate.mapping.KeyValue;
|
||||||
import org.hibernate.mapping.MappedSuperclass;
|
import org.hibernate.mapping.MappedSuperclass;
|
||||||
import org.hibernate.mapping.PersistentClass;
|
import org.hibernate.mapping.PersistentClass;
|
||||||
import org.hibernate.mapping.Property;
|
import org.hibernate.mapping.Property;
|
||||||
|
@ -428,6 +429,12 @@ public class MetadataContext {
|
||||||
//noinspection unchecked rawtypes
|
//noinspection unchecked rawtypes
|
||||||
( ( AttributeContainer) identifiableType ).getInFlightAccess().applyIdAttribute( idAttribute );
|
( ( 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 {
|
else {
|
||||||
// we have a non-aggregated composite-id
|
// 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) {
|
private EmbeddableTypeImpl<?> applyIdClassMetadata(Component idClassComponent) {
|
||||||
final JavaTypeRegistry registry = getTypeConfiguration()
|
final JavaTypeRegistry registry = getTypeConfiguration()
|
||||||
.getJavaTypeRegistry();
|
.getJavaTypeRegistry();
|
||||||
|
|
Loading…
Reference in New Issue