HHH-17460 - Ongoing JPA 32 work

This commit is contained in:
Steve Ebersole 2024-03-19 15:08:43 -05:00
parent 6260941790
commit 2cf379159b
10 changed files with 117 additions and 22 deletions

View File

@ -10,4 +10,6 @@ package org.hibernate.boot.jaxb.mapping.spi;
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public interface JaxbMappedSuperclass extends JaxbEntityOrMappedSuperclass { public interface JaxbMappedSuperclass extends JaxbEntityOrMappedSuperclass {
@Override
JaxbAttributesContainerImpl getAttributes();
} }

View File

@ -6,17 +6,17 @@
*/ */
package org.hibernate.boot.model.internal; package org.hibernate.boot.model.internal;
import java.util.Collection;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.annotations.Target; import org.hibernate.annotations.Target;
import org.hibernate.boot.spi.AccessType; import org.hibernate.boot.spi.AccessType;
import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.boot.spi.PropertyData; import org.hibernate.boot.spi.PropertyData;
import org.hibernate.models.internal.ClassTypeDetailsImpl; import org.hibernate.models.internal.ClassTypeDetailsImpl;
import org.hibernate.models.internal.dynamic.DynamicClassDetails;
import org.hibernate.models.spi.AnnotationUsage; import org.hibernate.models.spi.AnnotationUsage;
import org.hibernate.models.spi.ClassDetails; import org.hibernate.models.spi.ClassDetails;
import org.hibernate.models.spi.MemberDetails; import org.hibernate.models.spi.MemberDetails;
import org.hibernate.models.spi.SourceModelBuildingContext;
import org.hibernate.models.spi.TypeDetails; import org.hibernate.models.spi.TypeDetails;
import org.hibernate.models.spi.TypeVariableScope; import org.hibernate.models.spi.TypeVariableScope;
@ -83,7 +83,15 @@ public class PropertyInferredData implements PropertyData {
public TypeDetails getPropertyType() throws MappingException { public TypeDetails getPropertyType() throws MappingException {
final AnnotationUsage<org.hibernate.boot.internal.Target> targetAnnotation = propertyMember.getAnnotationUsage( org.hibernate.boot.internal.Target.class ); final AnnotationUsage<org.hibernate.boot.internal.Target> targetAnnotation = propertyMember.getAnnotationUsage( org.hibernate.boot.internal.Target.class );
if ( targetAnnotation != null ) { if ( targetAnnotation != null ) {
return new ClassTypeDetailsImpl( targetAnnotation.getClassDetails( "value" ), TypeDetails.Kind.CLASS ); final String targetName = targetAnnotation.getString( "value" );
final SourceModelBuildingContext sourceModelBuildingContext = buildingContext
.getMetadataCollector()
.getSourceModelBuildingContext();
final ClassDetails classDetails = sourceModelBuildingContext.getClassDetailsRegistry().resolveClassDetails(
targetName,
name -> new DynamicClassDetails( targetName, sourceModelBuildingContext )
);
return new ClassTypeDetailsImpl( classDetails, TypeDetails.Kind.CLASS );
} }
final AnnotationUsage<Target> legacyTargetAnnotation = propertyMember.getAnnotationUsage( Target.class ); final AnnotationUsage<Target> legacyTargetAnnotation = propertyMember.getAnnotationUsage( Target.class );
@ -98,7 +106,15 @@ public class PropertyInferredData implements PropertyData {
public TypeDetails getClassOrElementType() throws MappingException { public TypeDetails getClassOrElementType() throws MappingException {
final AnnotationUsage<org.hibernate.boot.internal.Target> annotationUsage = propertyMember.getAnnotationUsage( org.hibernate.boot.internal.Target.class ); final AnnotationUsage<org.hibernate.boot.internal.Target> annotationUsage = propertyMember.getAnnotationUsage( org.hibernate.boot.internal.Target.class );
if ( annotationUsage != null ) { if ( annotationUsage != null ) {
return new ClassTypeDetailsImpl( annotationUsage.getClassDetails( "value" ), TypeDetails.Kind.CLASS ); final String targetName = annotationUsage.getString( "value" );
final SourceModelBuildingContext sourceModelBuildingContext = buildingContext
.getMetadataCollector()
.getSourceModelBuildingContext();
final ClassDetails classDetails = sourceModelBuildingContext.getClassDetailsRegistry().resolveClassDetails(
targetName,
name -> new DynamicClassDetails( targetName, sourceModelBuildingContext )
);
return new ClassTypeDetailsImpl( classDetails, TypeDetails.Kind.CLASS );
} }
final AnnotationUsage<Target> legacyAnnotationUsage = propertyMember.getAnnotationUsage( Target.class ); final AnnotationUsage<Target> legacyAnnotationUsage = propertyMember.getAnnotationUsage( Target.class );

View File

@ -46,8 +46,6 @@ import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.models.ModelsException; import org.hibernate.models.ModelsException;
import org.hibernate.models.internal.ClassTypeDetailsImpl; import org.hibernate.models.internal.ClassTypeDetailsImpl;
import org.hibernate.models.internal.ModelsClassLogging; import org.hibernate.models.internal.ModelsClassLogging;
import org.hibernate.models.spi.MutableClassDetails;
import org.hibernate.models.spi.MutableMemberDetails;
import org.hibernate.models.internal.dynamic.DynamicClassDetails; import org.hibernate.models.internal.dynamic.DynamicClassDetails;
import org.hibernate.models.internal.dynamic.DynamicFieldDetails; import org.hibernate.models.internal.dynamic.DynamicFieldDetails;
import org.hibernate.models.spi.AnnotationUsage; import org.hibernate.models.spi.AnnotationUsage;
@ -56,6 +54,8 @@ import org.hibernate.models.spi.ClassDetailsRegistry;
import org.hibernate.models.spi.FieldDetails; import org.hibernate.models.spi.FieldDetails;
import org.hibernate.models.spi.MethodDetails; import org.hibernate.models.spi.MethodDetails;
import org.hibernate.models.spi.MutableAnnotationUsage; import org.hibernate.models.spi.MutableAnnotationUsage;
import org.hibernate.models.spi.MutableClassDetails;
import org.hibernate.models.spi.MutableMemberDetails;
import org.hibernate.models.spi.TypeDetails; import org.hibernate.models.spi.TypeDetails;
import org.hibernate.property.access.spi.BuiltInPropertyAccessStrategies; import org.hibernate.property.access.spi.BuiltInPropertyAccessStrategies;
@ -269,6 +269,41 @@ public class ManagedTypeProcessor {
classDetails.addField( member ); classDetails.addField( member );
} }
} }
else if ( jaxbManagedType instanceof JaxbMappedSuperclassImpl jaxbMappedSuperclass ) {
final JaxbAttributesContainerImpl attributes = jaxbMappedSuperclass.getAttributes();
if ( CollectionHelper.isNotEmpty( attributes.getIdAttributes() ) ) {
// <id/>
attributes.getIdAttributes().forEach( (jaxbId) -> {
final TypeDetails attributeJavaType = determineDynamicAttributeJavaType( jaxbId, xmlDocumentContext );
final DynamicFieldDetails member = new DynamicFieldDetails(
jaxbId.getName(),
attributeJavaType,
classDetails,
MEMBER_MODIFIERS,
false,
false,
xmlDocumentContext.getModelBuildingContext()
);
classDetails.addField( member );
} );
}
else {
// <embedded-id/>
final JaxbEmbeddedIdImpl embeddedId = attributes.getEmbeddedIdAttribute();
final TypeDetails attributeJavaType = determineDynamicAttributeJavaType( embeddedId, xmlDocumentContext );
final DynamicFieldDetails member = new DynamicFieldDetails(
embeddedId.getName(),
attributeJavaType,
classDetails,
MEMBER_MODIFIERS,
false,
false,
xmlDocumentContext.getModelBuildingContext()
);
classDetails.addField( member );
}
}
final JaxbAttributesContainer attributes = jaxbManagedType.getAttributes(); final JaxbAttributesContainer attributes = jaxbManagedType.getAttributes();
@ -599,10 +634,17 @@ public class ManagedTypeProcessor {
.resolveClassDetails( className ); .resolveClassDetails( className );
final AccessType classAccessType = coalesceSuppliedValues( final AccessType classAccessType = coalesceSuppliedValues(
// look on this <entity/>
jaxbEntity::getAccess, jaxbEntity::getAccess,
// look on the root <entity/>
jaxbRoot::getAccess, jaxbRoot::getAccess,
// look for @Access on the entity class
() -> determineAccessTypeFromClassAnnotations( classDetails ), () -> determineAccessTypeFromClassAnnotations( classDetails ),
// look for a default (PU metadata default) access
xmlDocumentContext.getPersistenceUnitMetadata()::getAccessType, xmlDocumentContext.getPersistenceUnitMetadata()::getAccessType,
// look at @Id/@EmbeddedId
() -> determineAccessTypeFromClassMembers( classDetails ),
// fallback to PROPERTY
() -> AccessType.PROPERTY () -> AccessType.PROPERTY
); );
@ -625,6 +667,10 @@ public class ManagedTypeProcessor {
return accessUsage.getAttributeValue( "value" ); return accessUsage.getAttributeValue( "value" );
} }
return null;
}
private static AccessType determineAccessTypeFromClassMembers(ClassDetails classDetails) {
for ( FieldDetails field : classDetails.getFields() ) { for ( FieldDetails field : classDetails.getFields() ) {
if ( field.getAnnotationUsage( Id.class ) != null if ( field.getAnnotationUsage( Id.class ) != null
|| field.getAnnotationUsage( EmbeddedId.class ) != null ) { || field.getAnnotationUsage( EmbeddedId.class ) != null ) {
@ -727,7 +773,14 @@ public class ManagedTypeProcessor {
); );
classDetails.addAnnotationUsage( XmlAnnotationHelper.createAccessAnnotation( classAccessType, classDetails, xmlDocumentContext ) ); classDetails.addAnnotationUsage( XmlAnnotationHelper.createAccessAnnotation( classAccessType, classDetails, xmlDocumentContext ) );
final JaxbAttributesContainer attributes = jaxbMappedSuperclass.getAttributes(); final JaxbAttributesContainerImpl attributes = jaxbMappedSuperclass.getAttributes();
processIdMappings(
attributes,
classAccessType,
classDetails,
ManagedTypeProcessor::adjustNonDynamicTypeMember,
xmlDocumentContext
);
AttributeProcessor.processAttributes( attributes, classDetails, classAccessType, xmlDocumentContext ); AttributeProcessor.processAttributes( attributes, classDetails, classAccessType, xmlDocumentContext );
processEntityOrMappedSuperclass( jaxbMappedSuperclass, classDetails, xmlDocumentContext ); processEntityOrMappedSuperclass( jaxbMappedSuperclass, classDetails, xmlDocumentContext );

View File

@ -1687,4 +1687,19 @@ public class XmlAnnotationHelper {
optionsAnn.setAttributeValue( "force", true ); optionsAnn.setAttributeValue( "force", true );
} }
} }
public static String determineTargetName(String explicitName, XmlDocumentContext xmlDocumentContext) {
final String qualifiedName = StringHelper.qualifyConditionallyIfNot(
xmlDocumentContext.getXmlDocument().getDefaults().getPackage(),
explicitName
);
final ClassDetails classDetails = xmlDocumentContext.getModelBuildingContext()
.getClassDetailsRegistry()
.findClassDetails( qualifiedName );
if ( classDetails != null ) {
return classDetails.getName();
}
return explicitName;
}
} }

View File

@ -50,14 +50,12 @@ public class ElementCollectionAttributeProcessing {
jaxbElementCollection.getFetch(), jaxbElementCollection.getFetch(),
elementCollectionAnn elementCollectionAnn
); );
final String targetClass = jaxbElementCollection.getTargetClass(); final String targetClass = jaxbElementCollection.getTargetClass();
if ( targetClass != null ) { if ( targetClass != null ) {
XmlProcessingHelper.applyAttributeIfSpecified( XmlProcessingHelper.applyAttributeIfSpecified(
"targetClass", "targetClass",
XmlAnnotationHelper.resolveJavaType( XmlAnnotationHelper.resolveJavaType( targetClass, xmlDocumentContext.getModelBuildingContext() ).determineRawClass(),
targetClass,
xmlDocumentContext.getModelBuildingContext()
).determineRawClass(),
elementCollectionAnn elementCollectionAnn
); );
} }

View File

@ -19,6 +19,7 @@ import org.hibernate.models.spi.MutableAnnotationUsage;
import jakarta.persistence.AccessType; import jakarta.persistence.AccessType;
import jakarta.persistence.Embedded; import jakarta.persistence.Embedded;
import static org.hibernate.boot.models.xml.internal.XmlAnnotationHelper.determineTargetName;
import static org.hibernate.boot.models.xml.internal.attr.CommonAttributeProcessing.applyAttributeBasics; import static org.hibernate.boot.models.xml.internal.attr.CommonAttributeProcessing.applyAttributeBasics;
import static org.hibernate.internal.util.NullnessHelper.coalesce; import static org.hibernate.internal.util.NullnessHelper.coalesce;
@ -42,7 +43,7 @@ public class EmbeddedAttributeProcessing {
if ( StringHelper.isNotEmpty( jaxbEmbedded.getTarget() ) ) { if ( StringHelper.isNotEmpty( jaxbEmbedded.getTarget() ) ) {
final MutableAnnotationUsage<Target> targetAnn = XmlProcessingHelper.getOrMakeAnnotation( Target.class, memberDetails, xmlDocumentContext ); final MutableAnnotationUsage<Target> targetAnn = XmlProcessingHelper.getOrMakeAnnotation( Target.class, memberDetails, xmlDocumentContext );
targetAnn.setAttributeValue( "value", jaxbEmbedded.getTarget() ); targetAnn.setAttributeValue( "value", determineTargetName( jaxbEmbedded.getTarget(), xmlDocumentContext ) );
} }
applyAttributeBasics( jaxbEmbedded, memberDetails, embeddedAnn, accessType, xmlDocumentContext ); applyAttributeBasics( jaxbEmbedded, memberDetails, embeddedAnn, accessType, xmlDocumentContext );

View File

@ -6,10 +6,12 @@
*/ */
package org.hibernate.boot.models.xml.internal.attr; package org.hibernate.boot.models.xml.internal.attr;
import org.hibernate.boot.internal.Target;
import org.hibernate.boot.jaxb.mapping.spi.JaxbEmbeddedIdImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbEmbeddedIdImpl;
import org.hibernate.boot.models.xml.internal.XmlAnnotationHelper; import org.hibernate.boot.models.xml.internal.XmlAnnotationHelper;
import org.hibernate.boot.models.xml.internal.XmlProcessingHelper; import org.hibernate.boot.models.xml.internal.XmlProcessingHelper;
import org.hibernate.boot.models.xml.spi.XmlDocumentContext; import org.hibernate.boot.models.xml.spi.XmlDocumentContext;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.models.spi.MutableClassDetails; import org.hibernate.models.spi.MutableClassDetails;
import org.hibernate.models.spi.MutableMemberDetails; import org.hibernate.models.spi.MutableMemberDetails;
import org.hibernate.models.spi.MutableAnnotationUsage; import org.hibernate.models.spi.MutableAnnotationUsage;
@ -17,6 +19,7 @@ import org.hibernate.models.spi.MutableAnnotationUsage;
import jakarta.persistence.AccessType; import jakarta.persistence.AccessType;
import jakarta.persistence.EmbeddedId; import jakarta.persistence.EmbeddedId;
import static org.hibernate.boot.models.xml.internal.XmlAnnotationHelper.determineTargetName;
import static org.hibernate.internal.util.NullnessHelper.coalesce; import static org.hibernate.internal.util.NullnessHelper.coalesce;
/** /**
@ -39,6 +42,11 @@ public class EmbeddedIdAttributeProcessing {
final MutableAnnotationUsage<EmbeddedId> idAnn = XmlProcessingHelper.makeAnnotation( EmbeddedId.class, memberDetails, xmlDocumentContext ); final MutableAnnotationUsage<EmbeddedId> idAnn = XmlProcessingHelper.makeAnnotation( EmbeddedId.class, memberDetails, xmlDocumentContext );
CommonAttributeProcessing.applyAttributeBasics( jaxbEmbeddedId, memberDetails, idAnn, accessType, xmlDocumentContext ); CommonAttributeProcessing.applyAttributeBasics( jaxbEmbeddedId, memberDetails, idAnn, accessType, xmlDocumentContext );
if ( StringHelper.isNotEmpty( jaxbEmbeddedId.getTarget() ) ) {
final MutableAnnotationUsage<Target> targetAnn = XmlProcessingHelper.getOrMakeAnnotation( Target.class, memberDetails, xmlDocumentContext );
targetAnn.setAttributeValue( "value", determineTargetName( jaxbEmbeddedId.getTarget(), xmlDocumentContext ) );
}
XmlAnnotationHelper.applyAttributeOverrides( jaxbEmbeddedId.getAttributeOverrides(), memberDetails, xmlDocumentContext ); XmlAnnotationHelper.applyAttributeOverrides( jaxbEmbeddedId.getAttributeOverrides(), memberDetails, xmlDocumentContext );
return memberDetails; return memberDetails;

View File

@ -28,6 +28,7 @@ import org.hibernate.models.spi.MutableMemberDetails;
import jakarta.persistence.AccessType; import jakarta.persistence.AccessType;
import jakarta.persistence.ManyToOne; import jakarta.persistence.ManyToOne;
import static org.hibernate.boot.models.xml.internal.XmlAnnotationHelper.determineTargetName;
import static org.hibernate.internal.util.NullnessHelper.coalesce; import static org.hibernate.internal.util.NullnessHelper.coalesce;
/** /**
@ -126,7 +127,7 @@ public class ManyToOneAttributeProcessing {
} }
final MutableAnnotationUsage<Target> targetAnn = XmlProcessingHelper.makeAnnotation( Target.class, memberDetails, xmlDocumentContext ); final MutableAnnotationUsage<Target> targetAnn = XmlProcessingHelper.makeAnnotation( Target.class, memberDetails, xmlDocumentContext );
targetAnn.setAttributeValue( "value", targetEntityName ); targetAnn.setAttributeValue( "value", determineTargetName( targetEntityName, xmlDocumentContext ) );
} }
private static <E extends Enum<E>> List<E> asList(EnumSet<E> enums) { private static <E extends Enum<E>> List<E> asList(EnumSet<E> enums) {

View File

@ -21,6 +21,7 @@ import jakarta.persistence.AccessType;
import jakarta.persistence.OneToOne; import jakarta.persistence.OneToOne;
import static org.hibernate.boot.models.xml.internal.XmlAnnotationHelper.applyCascading; import static org.hibernate.boot.models.xml.internal.XmlAnnotationHelper.applyCascading;
import static org.hibernate.boot.models.xml.internal.XmlAnnotationHelper.determineTargetName;
import static org.hibernate.boot.models.xml.internal.XmlProcessingHelper.getOrMakeAnnotation; import static org.hibernate.boot.models.xml.internal.XmlProcessingHelper.getOrMakeAnnotation;
import static org.hibernate.boot.models.xml.internal.attr.CommonAttributeProcessing.applyAttributeBasics; import static org.hibernate.boot.models.xml.internal.attr.CommonAttributeProcessing.applyAttributeBasics;
import static org.hibernate.internal.util.NullnessHelper.coalesce; import static org.hibernate.internal.util.NullnessHelper.coalesce;
@ -89,6 +90,7 @@ public class OneToOneAttributeProcessing {
} }
final MutableAnnotationUsage<Target> targetAnn = XmlProcessingHelper.makeAnnotation( Target.class, memberDetails, xmlDocumentContext ); final MutableAnnotationUsage<Target> targetAnn = XmlProcessingHelper.makeAnnotation( Target.class, memberDetails, xmlDocumentContext );
targetAnn.setAttributeValue( "value", targetEntityName ); targetAnn.setAttributeValue( "value", determineTargetName( targetEntityName, xmlDocumentContext ) );
} }
} }

View File

@ -26,6 +26,7 @@ import org.junit.jupiter.api.Test;
import jakarta.persistence.AccessType; import jakarta.persistence.AccessType;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
/** /**
@ -193,16 +194,14 @@ public class XmlAccessTest {
final Getter accessGetter = attributeMapping.getPropertyAccess().getGetter(); final Getter accessGetter = attributeMapping.getPropertyAccess().getGetter();
if ( AccessType.FIELD.equals( accessType ) ) { if ( AccessType.FIELD.equals( accessType ) ) {
assertTrue( assertThat( accessGetter )
accessGetter instanceof GetterFieldImpl, .withFailMessage( "FIELD access was expected." )
"Field access was expected." .isInstanceOf( GetterFieldImpl.class );
);
} }
else { else {
assertTrue( assertThat( accessGetter )
accessGetter instanceof GetterMethodImpl, .withFailMessage( "PROPERTY (method) access was expected." )
"Property access was expected." .isInstanceOf( GetterMethodImpl.class );
);
} }
} }
} }