Skip to content

Commit 84e5d19

Browse files
committed
HHH-19059 Fix check for property access fields on hierarchies
1 parent 2fd1191 commit 84e5d19

File tree

1 file changed

+49
-57
lines changed
  • hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy

1 file changed

+49
-57
lines changed

hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/EnhancerImpl.java

+49-57
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import jakarta.persistence.Entity;
1414
import jakarta.persistence.Id;
1515
import jakarta.persistence.MappedSuperclass;
16+
import jakarta.persistence.Transient;
1617
import jakarta.persistence.metamodel.Type;
1718
import net.bytebuddy.asm.Advice;
1819
import net.bytebuddy.description.annotation.AnnotationDescription;
@@ -74,6 +75,9 @@
7475
import static net.bytebuddy.matcher.ElementMatchers.isDefaultFinalizer;
7576
import static net.bytebuddy.matcher.ElementMatchers.isGetter;
7677
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;
7781

7882
public 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

Comments
 (0)