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