1010import java .util .List ;
1111import java .util .Map ;
1212
13+ import jakarta .persistence .GeneratedValue ;
1314import jakarta .persistence .MapKey ;
1415import jakarta .persistence .MapKeyClass ;
1516import jakarta .persistence .MapKeyColumn ;
2526import org .hibernate .annotations .Any ;
2627import org .hibernate .annotations .AttributeBinderType ;
2728import org .hibernate .annotations .CompositeType ;
29+ import org .hibernate .annotations .IdGeneratorType ;
2830import org .hibernate .annotations .Immutable ;
2931import org .hibernate .annotations .LazyGroup ;
3032import org .hibernate .annotations .ManyToAny ;
@@ -596,20 +598,22 @@ private static int addProperty(
596598 List <PropertyData > inFlightPropertyDataList ,
597599 MetadataBuildingContext context ,
598600 int idPropertyCounter ) {
601+ final InFlightMetadataCollector collector = context .getMetadataCollector ();
602+
599603 // see if inFlightPropertyDataList already contains a PropertyData for this name,
600604 // and if so, skip it...
601605 for ( PropertyData propertyData : inFlightPropertyDataList ) {
602606 if ( propertyData .getPropertyName ().equals ( property .resolveAttributeName () ) ) {
603- checkIdProperty ( property , propertyData );
607+ checkIdProperty ( property , propertyData , collector . getSourceModelBuildingContext () );
604608 // EARLY EXIT!!!
605609 return idPropertyCounter ;
606610 }
607611 }
608612
609- final ClassDetails declaringClass = propertyContainer .getDeclaringClass ();
610613 final TypeVariableScope ownerType = propertyContainer .getTypeAtStake ();
614+
611615 final PropertyData propertyAnnotatedElement = new PropertyInferredData (
612- declaringClass ,
616+ propertyContainer . getDeclaringClass () ,
613617 ownerType ,
614618 property ,
615619 propertyContainer .getClassLevelAccessType ().getType (),
@@ -622,31 +626,51 @@ private static int addProperty(
622626 if ( hasIdAnnotation ( element ) ) {
623627 inFlightPropertyDataList .add ( idPropertyCounter , propertyAnnotatedElement );
624628 if ( hasToOneAnnotation ( element ) ) {
625- context .getMetadataCollector ()
626- .addToOneAndIdProperty ( ownerType .determineRawClass (), propertyAnnotatedElement );
629+ collector .addToOneAndIdProperty ( ownerType .determineRawClass (), propertyAnnotatedElement );
627630 }
628631 idPropertyCounter ++;
629632 }
630633 else {
631634 inFlightPropertyDataList .add ( propertyAnnotatedElement );
632635 }
633636 if ( element .hasDirectAnnotationUsage ( MapsId .class ) ) {
634- context .getMetadataCollector ()
635- .addPropertyAnnotatedWithMapsId ( ownerType .determineRawClass (), propertyAnnotatedElement );
637+ collector .addPropertyAnnotatedWithMapsId ( ownerType .determineRawClass (), propertyAnnotatedElement );
636638 }
637639
638640 return idPropertyCounter ;
639641 }
640642
641- private static void checkIdProperty (MemberDetails property , PropertyData propertyData ) {
642- final Id incomingIdProperty = property . getDirectAnnotationUsage ( Id . class );
643+ private static void checkIdProperty (MemberDetails property , PropertyData propertyData , SourceModelBuildingContext context ) {
644+ final boolean incomingIdProperty = hasIdAnnotation ( property );
643645 final MemberDetails attributeMember = propertyData .getAttributeMember ();
644- final Id existingIdProperty = attributeMember .getDirectAnnotationUsage ( Id .class );
645- if ( incomingIdProperty != null && existingIdProperty == null ) {
646- throw new MappingException (
647- "Attribute '" + attributeMember .getName ()
648- + "' is declared by '" + attributeMember .getDeclaringType ().getName ()
649- + "' and may not be redeclared as an '@Id' by '" + property .getDeclaringType ().getName () + "'" );
646+ final boolean existingIdProperty = hasIdAnnotation ( attributeMember );
647+ if ( incomingIdProperty ) {
648+ if ( existingIdProperty ) {
649+ if ( property .hasDirectAnnotationUsage ( GeneratedValue .class )
650+ || !property .getMetaAnnotated ( IdGeneratorType .class , context ).isEmpty () ) {
651+ //TODO: it would be nice to allow a root @Entity to override an
652+ // @Id field declared by a @MappedSuperclass and change the
653+ // generator, but for now we don't seem to be able to detect
654+ // that case here
655+ throw new AnnotationException (
656+ "Attribute '" + attributeMember .getName ()
657+ + "' is declared as an '@Id' or '@EmbeddedId' property by '"
658+ + attributeMember .getDeclaringType ().getName ()
659+ + "' and so '" + property .getDeclaringType ().getName ()
660+ + "' may not respecify the generation strategy" );
661+ }
662+ }
663+ else {
664+ //TODO: it would be nice to allow a root @Entity to override a
665+ // field declared by a @MappedSuperclass, redeclaring it
666+ // as an @Id field, but for now we don't seem to be able
667+ // to detect that case here
668+ throw new AnnotationException (
669+ "Attribute '" + attributeMember .getName ()
670+ + "' is declared by '" + attributeMember .getDeclaringType ().getName ()
671+ + "' and may not be redeclared as an '@Id' or '@EmbeddedId' by '"
672+ + property .getDeclaringType ().getName () + "'" );
673+ }
650674 }
651675 }
652676
@@ -721,14 +745,17 @@ private static void buildProperty(
721745 MetadataBuildingContext context ,
722746 Map <ClassDetails , InheritanceState > inheritanceStatePerClass ,
723747 MemberDetails property ) {
748+
749+ if ( isPropertyOfRegularEmbeddable ( propertyHolder , isComponentEmbedded )
750+ && property .hasDirectAnnotationUsage (Id .class )) {
751+ throw new AnnotationException ("Member '" + property .getName ()
752+ + "' of embeddable class " + propertyHolder .getClassName () + " is annotated '@Id'" );
753+ }
754+
724755 final TypeDetails attributeTypeDetails =
725756 inferredData .getAttributeMember ().isPlural ()
726757 ? inferredData .getAttributeMember ().getType ()
727758 : inferredData .getClassOrElementType ();
728- final ClassDetails attributeClassDetails = attributeTypeDetails .determineRawClass ();
729- final ColumnsBuilder columnsBuilder =
730- new ColumnsBuilder ( propertyHolder , nullability , property , inferredData , entityBinder , context )
731- .extractMetadata ();
732759
733760 final PropertyBinder propertyBinder = propertyBinder (
734761 propertyHolder ,
@@ -741,17 +768,14 @@ private static void buildProperty(
741768 attributeTypeDetails
742769 );
743770
744- if ( isPropertyOfRegularEmbeddable ( propertyHolder , isComponentEmbedded )
745- && property .hasDirectAnnotationUsage (Id .class )) {
746- throw new AnnotationException ("Member '" + property .getName ()
747- + "' of embeddable class " + propertyHolder .getClassName () + " is annotated '@Id'" );
748- }
749-
750771 final LazyGroup lazyGroupAnnotation = property .getDirectAnnotationUsage ( LazyGroup .class );
751772 if ( lazyGroupAnnotation != null ) {
752773 propertyBinder .setLazyGroup ( lazyGroupAnnotation .value () );
753774 }
754775
776+ final ColumnsBuilder columnsBuilder =
777+ new ColumnsBuilder ( propertyHolder , nullability , property , inferredData , entityBinder , context )
778+ .extractMetadata ();
755779 final AnnotatedJoinColumns joinColumns = columnsBuilder .getJoinColumns ();
756780 final AnnotatedColumns columns = propertyBinder .bindProperty (
757781 propertyHolder ,
@@ -762,7 +786,7 @@ private static void buildProperty(
762786 isComponentEmbedded ,
763787 inSecondPass ,
764788 property ,
765- attributeClassDetails ,
789+ attributeTypeDetails . determineRawClass () ,
766790 columnsBuilder
767791 );
768792 addNaturalIds ( inSecondPass , property , columns , joinColumns , context );
0 commit comments