@@ -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