66
77import java .lang .annotation .Annotation ;
88import java .lang .invoke .MethodHandles ;
9+ import java .util .Collection ;
910import java .util .EnumSet ;
1011import java .util .List ;
1112import java .util .Map ;
1213
14+ import jakarta .persistence .MapKey ;
15+ import jakarta .persistence .MapKeyClass ;
16+ import jakarta .persistence .MapKeyColumn ;
17+ import jakarta .persistence .MapKeyEnumerated ;
18+ import jakarta .persistence .MapKeyJoinColumn ;
19+ import jakarta .persistence .MapKeyJoinColumns ;
20+ import jakarta .persistence .MapKeyTemporal ;
21+ import jakarta .persistence .OrderBy ;
22+ import jakarta .persistence .OrderColumn ;
1323import org .hibernate .AnnotationException ;
1424import org .hibernate .AssertionFailure ;
1525import org .hibernate .MappingException ;
3444import org .hibernate .generator .EventType ;
3545import org .hibernate .generator .EventTypeSets ;
3646import org .hibernate .internal .CoreMessageLogger ;
37- import org .hibernate .internal .util .collections .CollectionHelper ;
38- import org .hibernate .mapping .Collection ;
3947import org .hibernate .mapping .Component ;
4048import org .hibernate .mapping .Join ;
4149import org .hibernate .mapping .KeyValue ;
4957import org .hibernate .metamodel .spi .EmbeddableInstantiator ;
5058import org .hibernate .models .spi .AnnotationDescriptor ;
5159import org .hibernate .models .spi .AnnotationDescriptorRegistry ;
60+ import org .hibernate .models .spi .ArrayTypeDetails ;
5261import org .hibernate .models .spi .ClassDetails ;
5362import org .hibernate .models .spi .MemberDetails ;
5463import org .hibernate .models .spi .SourceModelBuildingContext ;
93102import static org .hibernate .boot .model .internal .ToOneBinder .bindOneToOne ;
94103import static org .hibernate .id .IdentifierGeneratorHelper .getForeignId ;
95104import static org .hibernate .internal .util .StringHelper .qualify ;
105+ import static org .hibernate .internal .util .collections .CollectionHelper .isEmpty ;
96106
97107/**
98108 * A stateful binder responsible for creating {@link Property} objects.
@@ -275,29 +285,29 @@ private Property makePropertyAndValue() {
275285
276286 @ SuppressWarnings ({"rawtypes" , "unchecked" })
277287 private void callAttributeBinders (Property property , Map <String , PersistentClass > persistentClasses ) {
278- final List <? extends Annotation > metaAnnotatedTargets = memberDetails . getMetaAnnotated (
279- AttributeBinderType .class ,
280- getSourceModelContext ()
281- );
282-
283- if ( CollectionHelper . isEmpty ( metaAnnotatedTargets ) ) {
284- return ;
285- }
286-
287- final AnnotationDescriptorRegistry descriptorRegistry = getSourceModelContext (). getAnnotationDescriptorRegistry ( );
288- for ( int i = 0 ; i < metaAnnotatedTargets . size (); i ++ ) {
289- final Annotation metaAnnotatedTarget = metaAnnotatedTargets . get ( i );
290- final AnnotationDescriptor <? extends Annotation > metaAnnotatedDescriptor = descriptorRegistry . getDescriptor ( metaAnnotatedTarget . annotationType () );
291- final AttributeBinderType binderTypeAnn = metaAnnotatedDescriptor . getDirectAnnotationUsage ( AttributeBinderType . class );
292- try {
293- final AttributeBinder binder = binderTypeAnn . binder (). getConstructor (). newInstance ();
294- final PersistentClass persistentClass = entityBinder != null
295- ? entityBinder . getPersistentClass ()
296- : persistentClasses . get ( holder . getEntityName () );
297- binder . bind ( metaAnnotatedTarget , buildingContext , persistentClass , property );
298- }
299- catch ( Exception e ) {
300- throw new AnnotationException ( "error processing @AttributeBinderType annotation '" + metaAnnotatedDescriptor . getAnnotationType (). getName () + "'" , e );
288+ final List <? extends Annotation > metaAnnotatedTargets =
289+ memberDetails . getMetaAnnotated ( AttributeBinderType .class , getSourceModelContext () );
290+
291+ if ( ! isEmpty ( metaAnnotatedTargets ) ) {
292+ final AnnotationDescriptorRegistry descriptorRegistry =
293+ getSourceModelContext (). getAnnotationDescriptorRegistry ();
294+ for ( int i = 0 ; i < metaAnnotatedTargets . size (); i ++ ) {
295+ final Annotation metaAnnotatedTarget = metaAnnotatedTargets . get ( i );
296+ final AnnotationDescriptor <? extends Annotation > metaAnnotatedDescriptor =
297+ descriptorRegistry . getDescriptor ( metaAnnotatedTarget . annotationType () );
298+ final AttributeBinderType binderTypeAnn =
299+ metaAnnotatedDescriptor . getDirectAnnotationUsage ( AttributeBinderType . class );
300+ try {
301+ final AttributeBinder binder = binderTypeAnn . binder (). getConstructor (). newInstance ( );
302+ final PersistentClass persistentClass = entityBinder != null
303+ ? entityBinder . getPersistentClass ()
304+ : persistentClasses . get ( holder . getEntityName () );
305+ binder . bind ( metaAnnotatedTarget , buildingContext , persistentClass , property );
306+ }
307+ catch ( Exception e ) {
308+ throw new AnnotationException ( "error processing @AttributeBinderType annotation '" +
309+ metaAnnotatedDescriptor . getAnnotationType (). getName () + "'" , e );
310+ }
301311 }
302312 }
303313 }
@@ -398,12 +408,14 @@ private Component getOrCreateCompositeId(RootClass rootClass) {
398408 private Class <? extends EmbeddableInstantiator > resolveCustomInstantiator (
399409 MemberDetails property ,
400410 ClassDetails embeddableClass ) {
401- final org .hibernate .annotations .EmbeddableInstantiator onEmbedded = property .getDirectAnnotationUsage ( org .hibernate .annotations .EmbeddableInstantiator .class );
411+ final org .hibernate .annotations .EmbeddableInstantiator onEmbedded =
412+ property .getDirectAnnotationUsage ( org .hibernate .annotations .EmbeddableInstantiator .class );
402413 if ( onEmbedded != null ) {
403414 return onEmbedded .value ();
404415 }
405416
406- final org .hibernate .annotations .EmbeddableInstantiator onEmbeddable = embeddableClass .getDirectAnnotationUsage ( org .hibernate .annotations .EmbeddableInstantiator .class );
417+ final org .hibernate .annotations .EmbeddableInstantiator onEmbeddable =
418+ embeddableClass .getDirectAnnotationUsage ( org .hibernate .annotations .EmbeddableInstantiator .class );
407419 if ( onEmbeddable != null ) {
408420 return onEmbeddable .value ();
409421 }
@@ -414,6 +426,7 @@ private Class<? extends EmbeddableInstantiator> resolveCustomInstantiator(
414426 //used when the value is provided and the binding is done elsewhere
415427 public Property makeProperty () {
416428 validateMake ();
429+ validateAnnotationsAgainstType ();
417430 LOG .debugf ( "Building property %s" , name );
418431 Property property = new Property ();
419432 property .setName ( name );
@@ -505,7 +518,7 @@ private void handleNaturalId(Property property) {
505518
506519 private void inferOptimisticLocking (Property property ) {
507520 // this is already handled for collections in CollectionBinder...
508- if ( value instanceof Collection collection ) {
521+ if ( value instanceof org . hibernate . mapping . Collection collection ) {
509522 property .setOptimisticLocked ( collection .isOptimisticLocked () );
510523 }
511524 else if ( memberDetails != null && memberDetails .hasDirectAnnotationUsage ( OptimisticLock .class ) ) {
@@ -519,6 +532,37 @@ else if ( memberDetails != null && memberDetails.hasDirectAnnotationUsage( Optim
519532 }
520533 }
521534
535+ private void validateAnnotationsAgainstType () {
536+ if ( memberDetails != null ) {
537+ if ( !(memberDetails .getType () instanceof ArrayTypeDetails ) ) {
538+ checkAnnotation ( OrderColumn .class , List .class );
539+ if ( memberDetails .hasDirectAnnotationUsage ( OrderBy .class )
540+ && !memberDetails .getType ().isImplementor ( Collection .class )
541+ && !memberDetails .getType ().isImplementor ( Map .class ) ) {
542+ throw new AnnotationException ( "Property '" + qualify ( holder .getPath (), name )
543+ + "' is annotated '@OrderBy' but is not of type 'Collection' or 'Map'" );
544+ }
545+ }
546+ checkAnnotation ( MapKey .class , Map .class );
547+ checkAnnotation ( MapKeyColumn .class , Map .class );
548+ checkAnnotation ( MapKeyClass .class , Map .class );
549+ checkAnnotation ( MapKeyEnumerated .class , Map .class );
550+ checkAnnotation ( MapKeyTemporal .class , Map .class );
551+ checkAnnotation ( MapKeyColumn .class , Map .class );
552+ checkAnnotation ( MapKeyJoinColumn .class , Map .class );
553+ checkAnnotation ( MapKeyJoinColumns .class , Map .class );
554+ }
555+ }
556+
557+ private void checkAnnotation (Class <? extends Annotation > annotationClass , Class <?> propertyType ) {
558+ if ( memberDetails .hasDirectAnnotationUsage ( annotationClass )
559+ && !memberDetails .getType ().isImplementor ( propertyType ) ) {
560+ throw new AnnotationException ( "Property '" + qualify ( holder .getPath (), name )
561+ + "' is annotated '@" + annotationClass .getSimpleName ()
562+ + "' but is not of type '" + propertyType .getTypeName () + "'" );
563+ }
564+ }
565+
522566 private void validateOptimisticLock (boolean excluded ) {
523567 if ( excluded ) {
524568 if ( memberDetails .hasDirectAnnotationUsage ( Version .class ) ) {
@@ -587,29 +631,32 @@ private static int addProperty(
587631 inFlightPropertyDataList .add ( 0 , propertyAnnotatedElement );
588632 handleIdProperty ( propertyContainer , context , declaringClass , ownerType , element );
589633 if ( hasToOneAnnotation ( element ) ) {
590- context .getMetadataCollector ().addToOneAndIdProperty ( ownerType .determineRawClass (), propertyAnnotatedElement );
634+ context .getMetadataCollector ()
635+ .addToOneAndIdProperty ( ownerType .determineRawClass (), propertyAnnotatedElement );
591636 }
592637 idPropertyCounter ++;
593638 }
594639 else {
595640 inFlightPropertyDataList .add ( propertyAnnotatedElement );
596641 }
597642 if ( element .hasDirectAnnotationUsage ( MapsId .class ) ) {
598- context .getMetadataCollector ().addPropertyAnnotatedWithMapsId ( ownerType .determineRawClass (), propertyAnnotatedElement );
643+ context .getMetadataCollector ()
644+ .addPropertyAnnotatedWithMapsId ( ownerType .determineRawClass (), propertyAnnotatedElement );
599645 }
600646
601647 return idPropertyCounter ;
602648 }
603649
604650 private static void checkIdProperty (MemberDetails property , PropertyData propertyData ) {
605651 final Id incomingIdProperty = property .getDirectAnnotationUsage ( Id .class );
606- final Id existingIdProperty = propertyData .getAttributeMember ().getDirectAnnotationUsage ( Id .class );
652+ final MemberDetails attributeMember = propertyData .getAttributeMember ();
653+ final Id existingIdProperty = attributeMember .getDirectAnnotationUsage ( Id .class );
607654 if ( incomingIdProperty != null && existingIdProperty == null ) {
608655 throw new MappingException (
609656 String .format (
610657 "You cannot override the [%s] non-identifier property from the [%s] base class or @MappedSuperclass and make it an identifier in the [%s] subclass" ,
611- propertyData . getAttributeMember () .getName (),
612- propertyData . getAttributeMember () .getDeclaringType ().getName (),
658+ attributeMember .getName (),
659+ attributeMember .getDeclaringType ().getName (),
613660 property .getDeclaringType ().getName ()
614661 )
615662 );
@@ -631,7 +678,8 @@ private static void handleIdProperty(
631678 if ( element .hasDirectAnnotationUsage ( Id .class ) && element .hasDirectAnnotationUsage ( Column .class ) ) {
632679 final String columnName = element .getDirectAnnotationUsage ( Column .class ).name ();
633680 declaringClass .forEachField ( (index , fieldDetails ) -> {
634- if ( !element .hasDirectAnnotationUsage ( MapsId .class ) && isJoinColumnPresent ( columnName , element , sourceModelContext ) ) {
681+ if ( !element .hasDirectAnnotationUsage ( MapsId .class )
682+ && isJoinColumnPresent ( columnName , element , sourceModelContext ) ) {
635683 //create a PropertyData for the specJ property holding the mapping
636684 context .getMetadataCollector ().addPropertyAnnotatedWithMapsIdSpecj (
637685 ownerType .determineRawClass (),
@@ -1157,7 +1205,8 @@ private static boolean isComposite(
11571205 MemberDetails property ,
11581206 ClassDetails returnedClass ,
11591207 PropertyData overridingProperty ) {
1160- final InheritanceState state = inheritanceStatePerClass .get ( overridingProperty .getClassOrElementType ().determineRawClass () );
1208+ final InheritanceState state =
1209+ inheritanceStatePerClass .get ( overridingProperty .getClassOrElementType ().determineRawClass () );
11611210 return state != null ? state .hasIdClassOrEmbeddedId () : isEmbedded ( property , returnedClass );
11621211 }
11631212
0 commit comments