3535import java .util .Collections ;
3636import java .util .HashSet ;
3737import java .util .List ;
38+ import java .util .Map ;
3839import java .util .Set ;
3940import java .util .concurrent .Callable ;
4041import java .util .concurrent .ConcurrentHashMap ;
4142import java .util .function .Predicate ;
4243import java .util .stream .Collectors ;
4344
45+ import org .graalvm .nativeimage .hosted .Feature ;
4446import org .graalvm .nativeimage .hosted .Feature .DuringAnalysisAccess ;
4547import org .graalvm .nativeimage .impl .ConfigurationPredicate ;
4648import org .graalvm .nativeimage .impl .RuntimeReflectionSupport ;
4749
4850import com .oracle .graal .pointsto .meta .AnalysisType ;
51+ import com .oracle .svm .core .TypeResult ;
4952import com .oracle .svm .core .hub .ClassForNameSupport ;
5053import com .oracle .svm .core .hub .DynamicHub ;
5154import com .oracle .svm .core .jdk .RecordSupport ;
5255import com .oracle .svm .core .util .UserError ;
5356import com .oracle .svm .core .util .VMError ;
57+ import com .oracle .svm .hosted .FeatureImpl ;
5458import com .oracle .svm .hosted .FeatureImpl .DuringAnalysisAccessImpl ;
5559import com .oracle .svm .hosted .FeatureImpl .FeatureAccessImpl ;
5660import com .oracle .svm .hosted .substitute .SubstitutionReflectivityFilter ;
@@ -72,6 +76,7 @@ public class ReflectionDataBuilder implements RuntimeReflectionSupport {
7276 private final Set <Field > reflectionFields = Collections .newSetFromMap (new ConcurrentHashMap <>());
7377
7478 /* Keep track of classes already processed for reflection. */
79+ private final Map <String , List <Runnable >> reachabilityHandlers = new ConcurrentHashMap <>();
7580 private final Set <Class <?>> processedClasses = new HashSet <>();
7681
7782 private final ReflectionDataAccessors accessors ;
@@ -111,6 +116,19 @@ private static DynamicHub.ReflectionData getArrayReflectionData() {
111116 @ Override
112117 public void register (ConfigurationPredicate predicate , Class <?>... classes ) {
113118 checkNotSealed ();
119+ registerPredicated (predicate , () -> registerClasses (classes ));
120+ }
121+
122+ private void registerPredicated (ConfigurationPredicate predicate , Runnable runnable ) {
123+ if (ConfigurationPredicate .DEFAULT_CONFIGRATION_PREDICATE .equals (predicate )) {
124+ runnable .run ();
125+ } else {
126+ List <Runnable > handlers = reachabilityHandlers .computeIfAbsent (predicate .getTypeReachability (), key -> new ArrayList <>());
127+ handlers .add (runnable );
128+ }
129+ }
130+
131+ private void registerClasses (Class <?>[] classes ) {
114132 for (Class <?> clazz : classes ) {
115133 if (reflectionClasses .add (clazz )) {
116134 modifiedClasses .add (clazz );
@@ -121,6 +139,10 @@ public void register(ConfigurationPredicate predicate, Class<?>... classes) {
121139 @ Override
122140 public void register (ConfigurationPredicate predicate , Executable ... methods ) {
123141 checkNotSealed ();
142+ registerPredicated (predicate , () -> registerMethods (methods ));
143+ }
144+
145+ private void registerMethods (Executable [] methods ) {
124146 for (Executable method : methods ) {
125147 if (reflectionMethods .add (method )) {
126148 modifiedClasses .add (method .getDeclaringClass ());
@@ -131,6 +153,10 @@ public void register(ConfigurationPredicate predicate, Executable... methods) {
131153 @ Override
132154 public void register (ConfigurationPredicate predicate , boolean finalIsWritable , Field ... fields ) {
133155 checkNotSealed ();
156+ registerPredicated (predicate , () -> registerFields (fields ));
157+ }
158+
159+ private void registerFields (Field [] fields ) {
134160 // Unsafe and write accesses are always enabled for fields because accessors use Unsafe.
135161 for (Field field : fields ) {
136162 if (reflectionFields .add (field )) {
@@ -145,8 +171,17 @@ private void checkNotSealed() {
145171 }
146172 }
147173
174+ void registerPredicatedConfig (Feature .BeforeAnalysisAccess b ) {
175+ for (Map .Entry <String , List <Runnable >> stringListEntry : reachabilityHandlers .entrySet ()) {
176+ TypeResult <Class <?>> typeResult = ((FeatureImpl .BeforeAnalysisAccessImpl ) b ).getImageClassLoader ().findClass (stringListEntry .getKey ());
177+ b .registerReachabilityHandler (access -> stringListEntry .getValue ().forEach (Runnable ::run ), typeResult .get ());
178+ }
179+ reachabilityHandlers .clear ();
180+ }
181+
148182 protected void duringAnalysis (DuringAnalysisAccess a ) {
149183 DuringAnalysisAccessImpl access = (DuringAnalysisAccessImpl ) a ;
184+ registerPredicatedConfig (a );
150185 processReachableTypes (access );
151186 processRegisteredElements (access );
152187 }
0 commit comments