1313import jakarta .persistence .Entity ;
1414import jakarta .persistence .Id ;
1515import jakarta .persistence .MappedSuperclass ;
16+ import jakarta .persistence .Transient ;
1617import jakarta .persistence .metamodel .Type ;
1718import net .bytebuddy .asm .Advice ;
1819import net .bytebuddy .description .annotation .AnnotationDescription ;
7475import static net .bytebuddy .matcher .ElementMatchers .isDefaultFinalizer ;
7576import static net .bytebuddy .matcher .ElementMatchers .isGetter ;
7677import 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 ;
7781
7882public class EnhancerImpl implements Enhancer {
7983
@@ -476,21 +480,13 @@ private static boolean hasMappingAnnotation(AnnotationList annotations) {
476480 || annotations .isAnnotationPresent ( Embeddable .class );
477481 }
478482
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 ;
492487 }
493- return found ;
488+
489+ return annotations .stream ().noneMatch ( a -> IGNORED_PERSISTENCE_ANNOTATIONS .contains ( a .getAnnotationType ().getName () ) );
494490 }
495491
496492 private static final Set <String > IGNORED_PERSISTENCE_ANNOTATIONS = Set .of (
@@ -503,6 +499,17 @@ else if ( !found && !IGNORED_PERSISTENCE_ANNOTATIONS.contains( annotationName )
503499 "jakarta.persistence.PreUpdate"
504500 );
505501
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+
506513 /**
507514 * Check whether an entity class ({@code managedCtClass}) has mismatched names between a persistent field and its
508515 * 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
545552 .asMethodList ()
546553 .filter ( isGetter ().or ( isSetter () ) );
547554 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 ) {
549557 // We only need to check this for AccessType.PROPERTY
550558 continue ;
551559 }
552560
553561 final String methodName = methodDescription .getActualName ();
554- String methodFieldName ;
562+ String fieldName ;
555563 if ( methodName .startsWith ( "get" ) || methodName .startsWith ( "set" ) ) {
556- methodFieldName = methodName .substring ( 3 );
564+ fieldName = methodName .substring ( 3 );
557565 }
558566 else {
559567 assert methodName .startsWith ( "is" );
560- methodFieldName = methodName .substring ( 2 );
568+ fieldName = methodName .substring ( 2 );
561569 }
562570 // 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 ()
571583 );
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 );
603595 }
604596 }
605597 }
0 commit comments