@@ -154,6 +154,8 @@ class HibernateValidatorProcessor {
154
154
155
155
private static final DotName REPEATABLE = DotName .createSimple (Repeatable .class .getName ());
156
156
157
+ private static final DotName GRAALVM_FEATURE = DotName .createSimple ("org.graalvm.nativeimage.hosted.Feature" );
158
+
157
159
private static final Pattern BUILT_IN_CONSTRAINT_REPEATABLE_CONTAINER_PATTERN = Pattern .compile ("\\ $List$" );
158
160
159
161
@ BuildStep
@@ -498,12 +500,12 @@ public void build(
498
500
499
501
for (AnnotationInstance annotation : annotationInstances ) {
500
502
if (annotation .target ().kind () == AnnotationTarget .Kind .FIELD ) {
501
- contributeClass (classNamesToBeValidated , indexView , annotation .target ().asField ().declaringClass (). name () );
503
+ contributeClass (classNamesToBeValidated , indexView , annotation .target ().asField ().declaringClass ());
502
504
reflectiveFields .produce (new ReflectiveFieldBuildItem (getClass ().getName (), annotation .target ().asField ()));
503
505
contributeClassMarkedForCascadingValidation (classNamesToBeValidated , indexView , consideredAnnotation ,
504
506
annotation .target ().asField ().type ());
505
507
} 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 ());
507
509
// we need to register the method for reflection as it could be a getter
508
510
reflectiveMethods
509
511
.produce (new ReflectiveMethodBuildItem (getClass ().getName (), annotation .target ().asMethod ()));
@@ -513,7 +515,7 @@ public void build(
513
515
annotation .target ().asMethod ());
514
516
} else if (annotation .target ().kind () == AnnotationTarget .Kind .METHOD_PARAMETER ) {
515
517
contributeClass (classNamesToBeValidated , indexView ,
516
- annotation .target ().asMethodParameter ().method ().declaringClass (). name () );
518
+ annotation .target ().asMethodParameter ().method ().declaringClass ());
517
519
// a getter does not have parameters so it's a pure method: no need for reflection in this case
518
520
contributeClassMarkedForCascadingValidation (classNamesToBeValidated , indexView , consideredAnnotation ,
519
521
// FIXME this won't work in the case of synthetic parameters
@@ -522,21 +524,21 @@ public void build(
522
524
contributeMethodsWithInheritedValidation (methodsWithInheritedValidation , indexView ,
523
525
annotation .target ().asMethodParameter ().method ());
524
526
} else if (annotation .target ().kind () == AnnotationTarget .Kind .CLASS ) {
525
- contributeClass (classNamesToBeValidated , indexView , annotation .target ().asClass (). name () );
527
+ contributeClass (classNamesToBeValidated , indexView , annotation .target ().asClass ());
526
528
// no need for reflection in the case of a class level constraint
527
529
} else if (annotation .target ().kind () == AnnotationTarget .Kind .TYPE ) {
528
530
// container element constraints
529
531
AnnotationTarget enclosingTarget = annotation .target ().asType ().enclosingTarget ();
530
532
if (enclosingTarget .kind () == AnnotationTarget .Kind .FIELD ) {
531
- contributeClass (classNamesToBeValidated , indexView , enclosingTarget .asField ().declaringClass (). name () );
533
+ contributeClass (classNamesToBeValidated , indexView , enclosingTarget .asField ().declaringClass ());
532
534
reflectiveFields .produce (new ReflectiveFieldBuildItem (getClass ().getName (), enclosingTarget .asField ()));
533
535
if (annotation .target ().asType ().target () != null ) {
534
536
contributeClassMarkedForCascadingValidation (classNamesToBeValidated , indexView ,
535
537
consideredAnnotation ,
536
538
annotation .target ().asType ().target ());
537
539
}
538
540
} else if (enclosingTarget .kind () == AnnotationTarget .Kind .METHOD ) {
539
- contributeClass (classNamesToBeValidated , indexView , enclosingTarget .asMethod ().declaringClass (). name () );
541
+ contributeClass (classNamesToBeValidated , indexView , enclosingTarget .asMethod ().declaringClass ());
540
542
reflectiveMethods
541
543
.produce (new ReflectiveMethodBuildItem (getClass ().getName (), enclosingTarget .asMethod ()));
542
544
if (annotation .target ().asType ().target () != null ) {
@@ -701,33 +703,62 @@ private static void contributeBuiltinConstraints(Set<String> builtinConstraints,
701
703
}
702
704
}
703
705
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 ());
706
712
707
- if (DotNames .OBJECT .equals (className )) {
713
+ if (DotNames .OBJECT .equals (classInfo . name () )) {
708
714
return ;
709
715
}
710
716
711
- for (ClassInfo subclass : indexView .getAllKnownSubclasses (className )) {
717
+ for (ClassInfo subclass : indexView .getAllKnownSubclasses (classInfo . name () )) {
712
718
if (Modifier .isAbstract (subclass .flags ())) {
713
719
// we can avoid adding the abstract classes here: either they are parent classes
714
720
// and they will be dealt with by Hibernate Validator or they are child classes
715
721
// without any proper implementation and we can ignore them.
716
722
continue ;
717
723
}
724
+ if (!isRuntimeClass (indexView , subclass )) {
725
+ return ;
726
+ }
718
727
classNamesCollector .add (subclass .name ());
719
728
}
720
- for (ClassInfo implementor : indexView .getAllKnownImplementors (className )) {
729
+ for (ClassInfo implementor : indexView .getAllKnownImplementors (classInfo . name () )) {
721
730
if (Modifier .isAbstract (implementor .flags ())) {
722
731
// we can avoid adding the abstract classes here: either they are parent classes
723
732
// and they will be dealt with by Hibernate Validator or they are child classes
724
733
// without any proper implementation and we can ignore them.
725
734
continue ;
726
735
}
736
+ if (!isRuntimeClass (indexView , implementor )) {
737
+ continue ;
738
+ }
727
739
classNamesCollector .add (implementor .name ());
728
740
}
729
741
}
730
742
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
+
731
762
private static void contributeClassMarkedForCascadingValidation (Set <DotName > classNamesCollector ,
732
763
IndexView indexView , DotName consideredAnnotation , Type type ) {
733
764
if (VALID != consideredAnnotation ) {
@@ -736,7 +767,10 @@ private static void contributeClassMarkedForCascadingValidation(Set<DotName> cla
736
767
737
768
DotName className = getClassName (type );
738
769
if (className != null ) {
739
- contributeClass (classNamesCollector , indexView , className );
770
+ ClassInfo classInfo = indexView .getClassByName (className );
771
+ if (classInfo != null ) {
772
+ contributeClass (classNamesCollector , indexView , classInfo );
773
+ }
740
774
}
741
775
}
742
776
0 commit comments