Skip to content

Commit 27b475b

Browse files
committed
Ignore GraalVM features in HibernateValidatorProcessor
Fixes #47033
1 parent 3cad250 commit 27b475b

File tree

1 file changed

+46
-12
lines changed

1 file changed

+46
-12
lines changed

Diff for: extensions/hibernate-validator/deployment/src/main/java/io/quarkus/hibernate/validator/deployment/HibernateValidatorProcessor.java

+46-12
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ class HibernateValidatorProcessor {
154154

155155
private static final DotName REPEATABLE = DotName.createSimple(Repeatable.class.getName());
156156

157+
private static final DotName GRAALVM_FEATURE = DotName.createSimple("org.graalvm.nativeimage.hosted.Feature");
158+
157159
private static final Pattern BUILT_IN_CONSTRAINT_REPEATABLE_CONTAINER_PATTERN = Pattern.compile("\\$List$");
158160

159161
@BuildStep
@@ -498,12 +500,12 @@ public void build(
498500

499501
for (AnnotationInstance annotation : annotationInstances) {
500502
if (annotation.target().kind() == AnnotationTarget.Kind.FIELD) {
501-
contributeClass(classNamesToBeValidated, indexView, annotation.target().asField().declaringClass().name());
503+
contributeClass(classNamesToBeValidated, indexView, annotation.target().asField().declaringClass());
502504
reflectiveFields.produce(new ReflectiveFieldBuildItem(getClass().getName(), annotation.target().asField()));
503505
contributeClassMarkedForCascadingValidation(classNamesToBeValidated, indexView, consideredAnnotation,
504506
annotation.target().asField().type());
505507
} else if (annotation.target().kind() == AnnotationTarget.Kind.METHOD) {
506-
contributeClass(classNamesToBeValidated, indexView, annotation.target().asMethod().declaringClass().name());
508+
contributeClass(classNamesToBeValidated, indexView, annotation.target().asMethod().declaringClass());
507509
// we need to register the method for reflection as it could be a getter
508510
reflectiveMethods
509511
.produce(new ReflectiveMethodBuildItem(getClass().getName(), annotation.target().asMethod()));
@@ -513,7 +515,7 @@ public void build(
513515
annotation.target().asMethod());
514516
} else if (annotation.target().kind() == AnnotationTarget.Kind.METHOD_PARAMETER) {
515517
contributeClass(classNamesToBeValidated, indexView,
516-
annotation.target().asMethodParameter().method().declaringClass().name());
518+
annotation.target().asMethodParameter().method().declaringClass());
517519
// a getter does not have parameters so it's a pure method: no need for reflection in this case
518520
contributeClassMarkedForCascadingValidation(classNamesToBeValidated, indexView, consideredAnnotation,
519521
// FIXME this won't work in the case of synthetic parameters
@@ -522,21 +524,21 @@ public void build(
522524
contributeMethodsWithInheritedValidation(methodsWithInheritedValidation, indexView,
523525
annotation.target().asMethodParameter().method());
524526
} else if (annotation.target().kind() == AnnotationTarget.Kind.CLASS) {
525-
contributeClass(classNamesToBeValidated, indexView, annotation.target().asClass().name());
527+
contributeClass(classNamesToBeValidated, indexView, annotation.target().asClass());
526528
// no need for reflection in the case of a class level constraint
527529
} else if (annotation.target().kind() == AnnotationTarget.Kind.TYPE) {
528530
// container element constraints
529531
AnnotationTarget enclosingTarget = annotation.target().asType().enclosingTarget();
530532
if (enclosingTarget.kind() == AnnotationTarget.Kind.FIELD) {
531-
contributeClass(classNamesToBeValidated, indexView, enclosingTarget.asField().declaringClass().name());
533+
contributeClass(classNamesToBeValidated, indexView, enclosingTarget.asField().declaringClass());
532534
reflectiveFields.produce(new ReflectiveFieldBuildItem(getClass().getName(), enclosingTarget.asField()));
533535
if (annotation.target().asType().target() != null) {
534536
contributeClassMarkedForCascadingValidation(classNamesToBeValidated, indexView,
535537
consideredAnnotation,
536538
annotation.target().asType().target());
537539
}
538540
} else if (enclosingTarget.kind() == AnnotationTarget.Kind.METHOD) {
539-
contributeClass(classNamesToBeValidated, indexView, enclosingTarget.asMethod().declaringClass().name());
541+
contributeClass(classNamesToBeValidated, indexView, enclosingTarget.asMethod().declaringClass());
540542
reflectiveMethods
541543
.produce(new ReflectiveMethodBuildItem(getClass().getName(), enclosingTarget.asMethod()));
542544
if (annotation.target().asType().target() != null) {
@@ -701,33 +703,62 @@ private static void contributeBuiltinConstraints(Set<String> builtinConstraints,
701703
}
702704
}
703705

704-
private static void contributeClass(Set<DotName> classNamesCollector, IndexView indexView, DotName className) {
705-
classNamesCollector.add(className);
706+
private static void contributeClass(Set<DotName> classNamesCollector, IndexView indexView, ClassInfo classInfo) {
707+
if (!isRuntimeClass(indexView, classInfo)) {
708+
return;
709+
}
710+
711+
classNamesCollector.add(classInfo.name());
706712

707-
if (DotNames.OBJECT.equals(className)) {
713+
if (DotNames.OBJECT.equals(classInfo.name())) {
708714
return;
709715
}
710716

711-
for (ClassInfo subclass : indexView.getAllKnownSubclasses(className)) {
717+
for (ClassInfo subclass : indexView.getAllKnownSubclasses(classInfo.name())) {
712718
if (Modifier.isAbstract(subclass.flags())) {
713719
// we can avoid adding the abstract classes here: either they are parent classes
714720
// and they will be dealt with by Hibernate Validator or they are child classes
715721
// without any proper implementation and we can ignore them.
716722
continue;
717723
}
724+
if (!isRuntimeClass(indexView, subclass)) {
725+
return;
726+
}
718727
classNamesCollector.add(subclass.name());
719728
}
720-
for (ClassInfo implementor : indexView.getAllKnownImplementors(className)) {
729+
for (ClassInfo implementor : indexView.getAllKnownImplementors(classInfo.name())) {
721730
if (Modifier.isAbstract(implementor.flags())) {
722731
// we can avoid adding the abstract classes here: either they are parent classes
723732
// and they will be dealt with by Hibernate Validator or they are child classes
724733
// without any proper implementation and we can ignore them.
725734
continue;
726735
}
736+
if (!isRuntimeClass(indexView, implementor)) {
737+
continue;
738+
}
727739
classNamesCollector.add(implementor.name());
728740
}
729741
}
730742

743+
private static boolean isRuntimeClass(IndexView indexView, ClassInfo classInfo) {
744+
// Note: we cannot check that the class is a runtime one with QuarkusClassLoader.isClassPresentAtRuntime() here
745+
// because generated classes have not been pushed yet to the class loader
746+
747+
if (classInfo.interfaceNames().contains(GRAALVM_FEATURE)) {
748+
return false;
749+
}
750+
751+
DotName enclosingClassName = classInfo.enclosingClassAlways();
752+
if (enclosingClassName != null) {
753+
ClassInfo enclosingClass = indexView.getClassByName(enclosingClassName);
754+
if (enclosingClass != null) {
755+
return isRuntimeClass(indexView, enclosingClass);
756+
}
757+
}
758+
759+
return true;
760+
}
761+
731762
private static void contributeClassMarkedForCascadingValidation(Set<DotName> classNamesCollector,
732763
IndexView indexView, DotName consideredAnnotation, Type type) {
733764
if (VALID != consideredAnnotation) {
@@ -736,7 +767,10 @@ private static void contributeClassMarkedForCascadingValidation(Set<DotName> cla
736767

737768
DotName className = getClassName(type);
738769
if (className != null) {
739-
contributeClass(classNamesCollector, indexView, className);
770+
ClassInfo classInfo = indexView.getClassByName(className);
771+
if (classInfo != null) {
772+
contributeClass(classNamesCollector, indexView, classInfo);
773+
}
740774
}
741775
}
742776

0 commit comments

Comments
 (0)