diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbMappedSuperclass.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbMappedSuperclass.java index 43f57280cf..dcbc00e13f 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbMappedSuperclass.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/JaxbMappedSuperclass.java @@ -10,4 +10,6 @@ package org.hibernate.boot.jaxb.mapping.spi; * @author Steve Ebersole */ public interface JaxbMappedSuperclass extends JaxbEntityOrMappedSuperclass { + @Override + JaxbAttributesContainerImpl getAttributes(); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyInferredData.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyInferredData.java index dc10688ab6..af6b71493e 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyInferredData.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyInferredData.java @@ -6,17 +6,17 @@ */ package org.hibernate.boot.model.internal; -import java.util.Collection; - import org.hibernate.MappingException; import org.hibernate.annotations.Target; import org.hibernate.boot.spi.AccessType; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.boot.spi.PropertyData; import org.hibernate.models.internal.ClassTypeDetailsImpl; +import org.hibernate.models.internal.dynamic.DynamicClassDetails; import org.hibernate.models.spi.AnnotationUsage; import org.hibernate.models.spi.ClassDetails; import org.hibernate.models.spi.MemberDetails; +import org.hibernate.models.spi.SourceModelBuildingContext; import org.hibernate.models.spi.TypeDetails; import org.hibernate.models.spi.TypeVariableScope; @@ -83,7 +83,15 @@ public class PropertyInferredData implements PropertyData { public TypeDetails getPropertyType() throws MappingException { final AnnotationUsage targetAnnotation = propertyMember.getAnnotationUsage( org.hibernate.boot.internal.Target.class ); 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 legacyTargetAnnotation = propertyMember.getAnnotationUsage( Target.class ); @@ -98,7 +106,15 @@ public class PropertyInferredData implements PropertyData { public TypeDetails getClassOrElementType() throws MappingException { final AnnotationUsage annotationUsage = propertyMember.getAnnotationUsage( org.hibernate.boot.internal.Target.class ); 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 legacyAnnotationUsage = propertyMember.getAnnotationUsage( Target.class ); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/ManagedTypeProcessor.java b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/ManagedTypeProcessor.java index d636ac0aee..8d43f772ba 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/ManagedTypeProcessor.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/ManagedTypeProcessor.java @@ -46,8 +46,6 @@ import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.models.ModelsException; import org.hibernate.models.internal.ClassTypeDetailsImpl; 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.DynamicFieldDetails; 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.MethodDetails; 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.property.access.spi.BuiltInPropertyAccessStrategies; @@ -269,6 +269,41 @@ public class ManagedTypeProcessor { classDetails.addField( member ); } } + else if ( jaxbManagedType instanceof JaxbMappedSuperclassImpl jaxbMappedSuperclass ) { + final JaxbAttributesContainerImpl attributes = jaxbMappedSuperclass.getAttributes(); + + if ( CollectionHelper.isNotEmpty( attributes.getIdAttributes() ) ) { + // + 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 { + // + 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(); @@ -599,10 +634,17 @@ public class ManagedTypeProcessor { .resolveClassDetails( className ); final AccessType classAccessType = coalesceSuppliedValues( + // look on this jaxbEntity::getAccess, + // look on the root jaxbRoot::getAccess, + // look for @Access on the entity class () -> determineAccessTypeFromClassAnnotations( classDetails ), + // look for a default (PU metadata default) access xmlDocumentContext.getPersistenceUnitMetadata()::getAccessType, + // look at @Id/@EmbeddedId + () -> determineAccessTypeFromClassMembers( classDetails ), + // fallback to PROPERTY () -> AccessType.PROPERTY ); @@ -625,6 +667,10 @@ public class ManagedTypeProcessor { return accessUsage.getAttributeValue( "value" ); } + return null; + } + + private static AccessType determineAccessTypeFromClassMembers(ClassDetails classDetails) { for ( FieldDetails field : classDetails.getFields() ) { if ( field.getAnnotationUsage( Id.class ) != null || field.getAnnotationUsage( EmbeddedId.class ) != null ) { @@ -727,7 +773,14 @@ public class ManagedTypeProcessor { ); 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 ); processEntityOrMappedSuperclass( jaxbMappedSuperclass, classDetails, xmlDocumentContext ); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/XmlAnnotationHelper.java b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/XmlAnnotationHelper.java index 8b630f5510..65e13d6bbe 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/XmlAnnotationHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/XmlAnnotationHelper.java @@ -1687,4 +1687,19 @@ public class XmlAnnotationHelper { 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; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/ElementCollectionAttributeProcessing.java b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/ElementCollectionAttributeProcessing.java index 4ae49863ed..00c651347a 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/ElementCollectionAttributeProcessing.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/ElementCollectionAttributeProcessing.java @@ -50,14 +50,12 @@ public class ElementCollectionAttributeProcessing { jaxbElementCollection.getFetch(), elementCollectionAnn ); + final String targetClass = jaxbElementCollection.getTargetClass(); if ( targetClass != null ) { XmlProcessingHelper.applyAttributeIfSpecified( "targetClass", - XmlAnnotationHelper.resolveJavaType( - targetClass, - xmlDocumentContext.getModelBuildingContext() - ).determineRawClass(), + XmlAnnotationHelper.resolveJavaType( targetClass, xmlDocumentContext.getModelBuildingContext() ).determineRawClass(), elementCollectionAnn ); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/EmbeddedAttributeProcessing.java b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/EmbeddedAttributeProcessing.java index 17f2e108f3..896a32434a 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/EmbeddedAttributeProcessing.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/EmbeddedAttributeProcessing.java @@ -19,6 +19,7 @@ import org.hibernate.models.spi.MutableAnnotationUsage; import jakarta.persistence.AccessType; 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.internal.util.NullnessHelper.coalesce; @@ -42,7 +43,7 @@ public class EmbeddedAttributeProcessing { if ( StringHelper.isNotEmpty( jaxbEmbedded.getTarget() ) ) { final MutableAnnotationUsage 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 ); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/EmbeddedIdAttributeProcessing.java b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/EmbeddedIdAttributeProcessing.java index 5d1be397af..7008e521bb 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/EmbeddedIdAttributeProcessing.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/EmbeddedIdAttributeProcessing.java @@ -6,10 +6,12 @@ */ 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.models.xml.internal.XmlAnnotationHelper; import org.hibernate.boot.models.xml.internal.XmlProcessingHelper; 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.MutableMemberDetails; import org.hibernate.models.spi.MutableAnnotationUsage; @@ -17,6 +19,7 @@ import org.hibernate.models.spi.MutableAnnotationUsage; import jakarta.persistence.AccessType; import jakarta.persistence.EmbeddedId; +import static org.hibernate.boot.models.xml.internal.XmlAnnotationHelper.determineTargetName; import static org.hibernate.internal.util.NullnessHelper.coalesce; /** @@ -39,6 +42,11 @@ public class EmbeddedIdAttributeProcessing { final MutableAnnotationUsage idAnn = XmlProcessingHelper.makeAnnotation( EmbeddedId.class, memberDetails, xmlDocumentContext ); CommonAttributeProcessing.applyAttributeBasics( jaxbEmbeddedId, memberDetails, idAnn, accessType, xmlDocumentContext ); + if ( StringHelper.isNotEmpty( jaxbEmbeddedId.getTarget() ) ) { + final MutableAnnotationUsage targetAnn = XmlProcessingHelper.getOrMakeAnnotation( Target.class, memberDetails, xmlDocumentContext ); + targetAnn.setAttributeValue( "value", determineTargetName( jaxbEmbeddedId.getTarget(), xmlDocumentContext ) ); + } + XmlAnnotationHelper.applyAttributeOverrides( jaxbEmbeddedId.getAttributeOverrides(), memberDetails, xmlDocumentContext ); return memberDetails; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/ManyToOneAttributeProcessing.java b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/ManyToOneAttributeProcessing.java index c57d31e3da..8080a64bc5 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/ManyToOneAttributeProcessing.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/ManyToOneAttributeProcessing.java @@ -28,6 +28,7 @@ import org.hibernate.models.spi.MutableMemberDetails; import jakarta.persistence.AccessType; import jakarta.persistence.ManyToOne; +import static org.hibernate.boot.models.xml.internal.XmlAnnotationHelper.determineTargetName; import static org.hibernate.internal.util.NullnessHelper.coalesce; /** @@ -126,7 +127,7 @@ public class ManyToOneAttributeProcessing { } final MutableAnnotationUsage targetAnn = XmlProcessingHelper.makeAnnotation( Target.class, memberDetails, xmlDocumentContext ); - targetAnn.setAttributeValue( "value", targetEntityName ); + targetAnn.setAttributeValue( "value", determineTargetName( targetEntityName, xmlDocumentContext ) ); } private static > List asList(EnumSet enums) { diff --git a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/OneToOneAttributeProcessing.java b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/OneToOneAttributeProcessing.java index 8d4815f3cc..0f5ee93552 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/OneToOneAttributeProcessing.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/models/xml/internal/attr/OneToOneAttributeProcessing.java @@ -21,6 +21,7 @@ import jakarta.persistence.AccessType; import jakarta.persistence.OneToOne; 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.attr.CommonAttributeProcessing.applyAttributeBasics; import static org.hibernate.internal.util.NullnessHelper.coalesce; @@ -89,6 +90,7 @@ public class OneToOneAttributeProcessing { } final MutableAnnotationUsage targetAnn = XmlProcessingHelper.makeAnnotation( Target.class, memberDetails, xmlDocumentContext ); - targetAnn.setAttributeValue( "value", targetEntityName ); + targetAnn.setAttributeValue( "value", determineTargetName( targetEntityName, xmlDocumentContext ) ); } + } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/binding/annotations/access/xml/XmlAccessTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/binding/annotations/access/xml/XmlAccessTest.java index 771aebf513..a20370785b 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/binding/annotations/access/xml/XmlAccessTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/binding/annotations/access/xml/XmlAccessTest.java @@ -26,6 +26,7 @@ import org.junit.jupiter.api.Test; import jakarta.persistence.AccessType; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertTrue; /** @@ -193,16 +194,14 @@ public class XmlAccessTest { final Getter accessGetter = attributeMapping.getPropertyAccess().getGetter(); if ( AccessType.FIELD.equals( accessType ) ) { - assertTrue( - accessGetter instanceof GetterFieldImpl, - "Field access was expected." - ); + assertThat( accessGetter ) + .withFailMessage( "FIELD access was expected." ) + .isInstanceOf( GetterFieldImpl.class ); } else { - assertTrue( - accessGetter instanceof GetterMethodImpl, - "Property access was expected." - ); + assertThat( accessGetter ) + .withFailMessage( "PROPERTY (method) access was expected." ) + .isInstanceOf( GetterMethodImpl.class ); } } }