13
13
import jakarta .persistence .Entity ;
14
14
import jakarta .persistence .Id ;
15
15
import jakarta .persistence .MappedSuperclass ;
16
+ import jakarta .persistence .Transient ;
16
17
import jakarta .persistence .metamodel .Type ;
17
18
import net .bytebuddy .asm .Advice ;
18
19
import net .bytebuddy .description .annotation .AnnotationDescription ;
74
75
import static net .bytebuddy .matcher .ElementMatchers .isDefaultFinalizer ;
75
76
import static net .bytebuddy .matcher .ElementMatchers .isGetter ;
76
77
import static net .bytebuddy .matcher .ElementMatchers .isSetter ;
78
+ import static net .bytebuddy .matcher .ElementMatchers .isStatic ;
79
+ import static net .bytebuddy .matcher .ElementMatchers .named ;
80
+ import static net .bytebuddy .matcher .ElementMatchers .not ;
77
81
78
82
public class EnhancerImpl implements Enhancer {
79
83
@@ -476,21 +480,13 @@ private static boolean hasMappingAnnotation(AnnotationList annotations) {
476
480
|| annotations .isAnnotationPresent ( Embeddable .class );
477
481
}
478
482
479
- private static boolean hasPersistenceAnnotation (AnnotationList annotations ) {
480
- boolean found = false ;
481
- for ( AnnotationDescription annotation : annotations ) {
482
- final String annotationName = annotation .getAnnotationType ().getName ();
483
- if ( annotationName .startsWith ( "jakarta.persistence" ) ) {
484
- if ( annotationName .equals ( "jakarta.persistence.Transient" ) ) {
485
- // transient property so ignore it
486
- return false ;
487
- }
488
- else if ( !found && !IGNORED_PERSISTENCE_ANNOTATIONS .contains ( annotationName ) ) {
489
- found = true ;
490
- }
491
- }
483
+ private static boolean isPersistentMethod (MethodDescription method ) {
484
+ final AnnotationList annotations = method .getDeclaredAnnotations ();
485
+ if ( annotations .isAnnotationPresent ( Transient .class ) ) {
486
+ return false ;
492
487
}
493
- return found ;
488
+
489
+ return annotations .stream ().noneMatch ( a -> IGNORED_PERSISTENCE_ANNOTATIONS .contains ( a .getAnnotationType ().getName () ) );
494
490
}
495
491
496
492
private static final Set <String > IGNORED_PERSISTENCE_ANNOTATIONS = Set .of (
@@ -503,6 +499,17 @@ else if ( !found && !IGNORED_PERSISTENCE_ANNOTATIONS.contains( annotationName )
503
499
"jakarta.persistence.PreUpdate"
504
500
);
505
501
502
+ private static boolean containsField (Generic type , String fieldName ) {
503
+ do {
504
+ if ( !type .getDeclaredFields ().filter ( not ( isStatic () ).and ( named ( fieldName ) ) ).isEmpty () ) {
505
+ return true ;
506
+ }
507
+ type = type .getSuperClass ();
508
+ }
509
+ while ( type != null && !type .represents ( Object .class ) );
510
+ return false ;
511
+ }
512
+
506
513
/**
507
514
* Check whether an entity class ({@code managedCtClass}) has mismatched names between a persistent field and its
508
515
* getter/setter when using {@link AccessType#PROPERTY}, which Hibernate does not currently support for enhancement.
@@ -545,61 +552,46 @@ private static boolean checkUnsupportedAttributeNaming(TypeDescription managedCt
545
552
.asMethodList ()
546
553
.filter ( isGetter ().or ( isSetter () ) );
547
554
for ( final MethodDescription methodDescription : methods ) {
548
- if ( determineAccessType ( methodDescription , defaultAccessType ) != AccessType .PROPERTY ) {
555
+ if ( methodDescription .getDeclaringType ().represents ( Object .class )
556
+ || determineAccessType ( methodDescription , defaultAccessType ) != AccessType .PROPERTY ) {
549
557
// We only need to check this for AccessType.PROPERTY
550
558
continue ;
551
559
}
552
560
553
561
final String methodName = methodDescription .getActualName ();
554
- String methodFieldName ;
562
+ String fieldName ;
555
563
if ( methodName .startsWith ( "get" ) || methodName .startsWith ( "set" ) ) {
556
- methodFieldName = methodName .substring ( 3 );
564
+ fieldName = methodName .substring ( 3 );
557
565
}
558
566
else {
559
567
assert methodName .startsWith ( "is" );
560
- methodFieldName = methodName .substring ( 2 );
568
+ fieldName = methodName .substring ( 2 );
561
569
}
562
570
// convert first field letter to lower case
563
- methodFieldName = getJavaBeansFieldName ( methodFieldName );
564
- if ( methodFieldName != null && hasPersistenceAnnotation ( methodDescription .getDeclaredAnnotations () ) ) {
565
- boolean propertyNameMatchesFieldName = false ;
566
- for ( final FieldDescription field : methodDescription .getDeclaringType ().getDeclaredFields () ) {
567
- if ( !Modifier .isStatic ( field .getModifiers () ) ) {
568
- final AnnotatedFieldDescription annotatedField = new AnnotatedFieldDescription (
569
- enhancementContext ,
570
- field
571
+ fieldName = getJavaBeansFieldName ( fieldName );
572
+ if ( fieldName != null && isPersistentMethod ( methodDescription )
573
+ && !containsField ( managedCtClass .asGenericType (), fieldName ) ) {
574
+ // We shouldn't even be in this method if using LEGACY, see top of this method.
575
+ switch ( strategy ) {
576
+ case SKIP :
577
+ log .debugf (
578
+ "Skipping enhancement of [%s] because no field named [%s] could be found for property accessor method [%s]."
579
+ + " To fix this, make sure all property accessor methods have a matching field." ,
580
+ managedCtClass .getName (),
581
+ fieldName ,
582
+ methodDescription .getName ()
571
583
);
572
- if ( enhancementContext .isPersistentField ( annotatedField ) ) {
573
- if ( methodFieldName .equals ( field .getActualName () ) ) {
574
- propertyNameMatchesFieldName = true ;
575
- break ;
576
- }
577
- }
578
- }
579
- }
580
- if ( !propertyNameMatchesFieldName ) {
581
- // We shouldn't even be in this method if using LEGACY, see top of this method.
582
- switch ( strategy ) {
583
- case SKIP :
584
- log .debugf (
585
- "Skipping enhancement of [%s] because no field named [%s] could be found for property accessor method [%s]."
586
- + " To fix this, make sure all property accessor methods have a matching field." ,
587
- managedCtClass .getName (),
588
- methodFieldName ,
589
- methodDescription .getName ()
590
- );
591
- return true ;
592
- case FAIL :
593
- throw new EnhancementException ( String .format (
594
- "Enhancement of [%s] failed because no field named [%s] could be found for property accessor method [%s]."
595
- + " To fix this, make sure all property accessor methods have a matching field." ,
596
- managedCtClass .getName (),
597
- methodFieldName ,
598
- methodDescription .getName ()
599
- ) );
600
- default :
601
- throw new AssertionFailure ( "Unexpected strategy at this point: " + strategy );
602
- }
584
+ return true ;
585
+ case FAIL :
586
+ throw new EnhancementException ( String .format (
587
+ "Enhancement of [%s] failed because no field named [%s] could be found for property accessor method [%s]."
588
+ + " To fix this, make sure all property accessor methods have a matching field." ,
589
+ managedCtClass .getName (),
590
+ fieldName ,
591
+ methodDescription .getName ()
592
+ ) );
593
+ default :
594
+ throw new AssertionFailure ( "Unexpected strategy at this point: " + strategy );
603
595
}
604
596
}
605
597
}
0 commit comments