2525package com .oracle .svm .hosted ;
2626
2727import java .io .IOException ;
28+ import java .lang .reflect .Constructor ;
2829import java .lang .reflect .Method ;
2930import java .net .URL ;
3031import java .security .SecureClassLoader ;
3132import java .util .Collections ;
3233import java .util .Enumeration ;
34+ import java .util .List ;
3335import java .util .Set ;
3436import java .util .WeakHashMap ;
3537import java .util .jar .JarFile ;
@@ -135,34 +137,56 @@ public boolean isDisallowedClassLoader(ClassLoader c) {
135137 private static final Method defineClass = ReflectionUtil .lookupMethod (ClassLoader .class , "defineClass" ,
136138 String .class , byte [].class , int .class , int .class );
137139
138- static Class <?> loadClass (ClassLoader classLoader , String name , boolean resolve ) throws ClassNotFoundException {
139- Class <?> loadedClass = null ;
140+ private static final Constructor <Enumeration <?>> compoundEnumerationConstructor ;
141+ static {
142+ /* Reuse utility class defined as package-private class in java.lang.ClassLoader.java */
143+ String className = "java.lang.CompoundEnumeration" ;
140144 try {
141- /* invoke the "loadClass" method on the current class loader */
142- loadedClass = ((Class <?>) loadClass .invoke (classLoader , name , resolve ));
143- } catch (Exception e ) {
144- if (e .getCause () instanceof ClassNotFoundException ) {
145- throw ((ClassNotFoundException ) e .getCause ());
145+ @ SuppressWarnings ("unchecked" )
146+ Class <Enumeration <?>> compoundEnumerationClass = (Class <Enumeration <?>>) Class .forName (className );
147+ compoundEnumerationConstructor = ReflectionUtil .lookupConstructor (compoundEnumerationClass , Enumeration [].class );
148+ } catch (ClassNotFoundException | ReflectionUtil .ReflectionUtilError e ) {
149+ throw VMError .shouldNotReachHere ("Unable to get access to class " + className , e );
150+ }
151+ }
152+
153+ private static Class <?> loadClass (List <ClassLoader > activeClassLoaders , String name , boolean resolve ) throws ClassNotFoundException {
154+ ClassNotFoundException classNotFoundException = null ;
155+ for (ClassLoader loader : activeClassLoaders ) {
156+ try {
157+ /* invoke the "loadClass" method on the current class loader */
158+ return ((Class <?>) loadClass .invoke (loader , name , resolve ));
159+ } catch (Exception e ) {
160+ if (e .getCause () instanceof ClassNotFoundException ) {
161+ classNotFoundException = ((ClassNotFoundException ) e .getCause ());
162+ } else {
163+ String message = String .format ("Can not load class: %s, with class loader: %s" , name , loader );
164+ VMError .shouldNotReachHere (message , e );
165+ }
146166 }
147- String message = String .format ("Can not load class: %s, with class loader: %s" , name , classLoader );
148- VMError .shouldNotReachHere (message , e );
149167 }
150- return loadedClass ;
168+ VMError .guarantee (classNotFoundException != null );
169+ throw classNotFoundException ;
151170 }
152171
153- static URL findResource (ClassLoader classLoader , String name ) {
154- try {
155- // invoke the "findResource" method on the current class loader
156- return (URL ) findResource .invoke (classLoader , name );
157- } catch (ReflectiveOperationException e ) {
158- String message = String .format ("Can not find resource: %s using class loader: %s" , name , classLoader );
159- VMError .shouldNotReachHere (message , e );
172+ private static URL findResource (List <ClassLoader > activeClassLoaders , String name ) {
173+ for (ClassLoader loader : activeClassLoaders ) {
174+ try {
175+ // invoke the "findResource" method on the current class loader
176+ Object url = findResource .invoke (loader , name );
177+ if (url != null ) {
178+ return (URL ) url ;
179+ }
180+ } catch (ReflectiveOperationException | ClassCastException e ) {
181+ String message = String .format ("Can not find resource: %s using class loader: %s" , name , loader );
182+ VMError .shouldNotReachHere (message , e );
183+ }
160184 }
161185 return null ;
162186 }
163187
164188 @ SuppressWarnings ("unchecked" )
165- static Enumeration <URL > findResources (ClassLoader classLoader , String name ) {
189+ private static Enumeration <URL > findResources (ClassLoader classLoader , String name ) {
166190 try {
167191 // invoke the "findResources" method on the current class loader
168192 return (Enumeration <URL >) findResources .invoke (classLoader , name );
@@ -186,22 +210,38 @@ static Class<?> defineClass(ClassLoader classLoader, String name, byte[] b, int
186210
187211 @ Override
188212 protected Class <?> loadClass (String name , boolean resolve ) throws ClassNotFoundException {
189- return loadClass (getActiveClassLoader (), name , resolve );
213+ return loadClass (getActiveClassLoaders (), name , resolve );
190214 }
191215
192216 @ Override
193217 protected URL findResource (String name ) {
194- return findResource (getActiveClassLoader (), name );
218+ return findResource (getActiveClassLoaders (), name );
195219 }
196220
197221 @ Override
198222 protected Enumeration <URL > findResources (String name ) throws IOException {
199- return findResources (getActiveClassLoader (), name );
223+ List <ClassLoader > activeClassLoaders = getActiveClassLoaders ();
224+ assert !activeClassLoaders .isEmpty () & activeClassLoaders .size () <= 2 ;
225+ ClassLoader activeClassLoader = activeClassLoaders .get (0 );
226+ ClassLoader activeClassLoaderParent = activeClassLoaders .size () > 1 ? activeClassLoaders .get (1 ) : null ;
227+ if (activeClassLoaderParent != null ) {
228+ return newCompoundEnumeration (findResources (activeClassLoaderParent , name ), findResources (activeClassLoader , name ));
229+ }
230+ return findResources (activeClassLoader , name );
231+ }
232+
233+ @ SuppressWarnings ("unchecked" )
234+ private static <T > Enumeration <T > newCompoundEnumeration (Enumeration <?>... enums ) {
235+ try {
236+ return (Enumeration <T >) compoundEnumerationConstructor .newInstance ((Object ) enums );
237+ } catch (ReflectiveOperationException e ) {
238+ throw VMError .shouldNotReachHere ("Cannot instantiate CompoundEnumeration" , e );
239+ }
200240 }
201241
202242 public Class <?> forNameOrNull (String name , boolean initialize ) {
203243 try {
204- return Class .forName (name , initialize , getActiveClassLoader ( ));
244+ return Class .forName (name , initialize , getActiveClassLoaders (). get ( 0 ));
205245 } catch (LinkageError | ClassNotFoundException ignored ) {
206246 return null ;
207247 }
@@ -212,7 +252,7 @@ public Class<?> predefineClass(String name, byte[] array, int offset, int length
212252 if (forNameOrNull (name , false ) != null ) {
213253 throw VMError .shouldNotReachHere ("The class loader hierarchy already provides a class with the same name as the class submitted for predefinition: " + name );
214254 }
215- return defineClass (getActiveClassLoader ( ), name , array , offset , length );
255+ return defineClass (getActiveClassLoaders (). get ( 0 ), name , array , offset , length );
216256 }
217257
218258 @ Override
@@ -224,11 +264,18 @@ public String toString() {
224264 '}' ;
225265 }
226266
227- private ClassLoader getActiveClassLoader () {
228- ClassLoader delegate = nativeImageClassLoader ;
229- return delegate != null
230- ? delegate
231- : defaultSystemClassLoader ;
267+ private List <ClassLoader > getActiveClassLoaders () {
268+ ClassLoader activeClassLoader = nativeImageClassLoader ;
269+ if (activeClassLoader != null ) {
270+ ClassLoader activeClassLoaderParent = activeClassLoader .getParent ();
271+ if (activeClassLoaderParent instanceof NativeImageClassLoaderSupport .ClassPathClassLoader ) {
272+ return List .of (activeClassLoader , activeClassLoaderParent );
273+ } else {
274+ return List .of (activeClassLoader );
275+ }
276+ } else {
277+ return List .of (defaultSystemClassLoader );
278+ }
232279 }
233280
234281 /**
0 commit comments