Skip to content

Commit bcef040

Browse files
committed
Make NativeImageSystemClassLoader able to handle having module classloader with a parent ClassPathClassLoader
1 parent 1152923 commit bcef040

File tree

2 files changed

+81
-29
lines changed

2 files changed

+81
-29
lines changed

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageClassLoaderSupport.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,13 +102,19 @@ public class NativeImageClassLoaderSupport {
102102
public final ModuleLayer moduleLayerForImageBuild;
103103
public final ModuleFinder modulepathModuleFinder;
104104

105+
static final class ClassPathClassLoader extends URLClassLoader {
106+
public ClassPathClassLoader(URL[] urls, ClassLoader parent) {
107+
super(urls, parent);
108+
}
109+
}
110+
105111
protected NativeImageClassLoaderSupport(ClassLoader defaultSystemClassLoader, String[] classpath, String[] modulePath) {
106112

107113
classes = EconomicMap.create();
108114
packages = EconomicMap.create();
109115
emptySet = EconomicSet.create();
110116

111-
classPathClassLoader = new URLClassLoader(Util.verifyClassPathAndConvertToURLs(classpath), defaultSystemClassLoader);
117+
classPathClassLoader = new ClassPathClassLoader(Util.verifyClassPathAndConvertToURLs(classpath), defaultSystemClassLoader);
112118

113119
imagecp = Arrays.stream(classPathClassLoader.getURLs())
114120
.map(Util::urlToPath)

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/NativeImageSystemClassLoader.java

Lines changed: 74 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,13 @@
2525
package com.oracle.svm.hosted;
2626

2727
import java.io.IOException;
28+
import java.lang.reflect.Constructor;
2829
import java.lang.reflect.Method;
2930
import java.net.URL;
3031
import java.security.SecureClassLoader;
3132
import java.util.Collections;
3233
import java.util.Enumeration;
34+
import java.util.List;
3335
import java.util.Set;
3436
import java.util.WeakHashMap;
3537
import java.util.jar.JarFile;
@@ -135,34 +137,55 @@ 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+
} catch (ReflectiveOperationException | ClassCastException e) {
180+
String message = String.format("Can not find resource: %s using class loader: %s", name, loader);
181+
VMError.shouldNotReachHere(message, e);
182+
}
160183
}
161184
return null;
162185
}
163186

164187
@SuppressWarnings("unchecked")
165-
static Enumeration<URL> findResources(ClassLoader classLoader, String name) {
188+
private static Enumeration<URL> findResources(ClassLoader classLoader, String name) {
166189
try {
167190
// invoke the "findResources" method on the current class loader
168191
return (Enumeration<URL>) findResources.invoke(classLoader, name);
@@ -186,22 +209,38 @@ static Class<?> defineClass(ClassLoader classLoader, String name, byte[] b, int
186209

187210
@Override
188211
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
189-
return loadClass(getActiveClassLoader(), name, resolve);
212+
return loadClass(getActiveClassLoaders(), name, resolve);
190213
}
191214

192215
@Override
193216
protected URL findResource(String name) {
194-
return findResource(getActiveClassLoader(), name);
217+
return findResource(getActiveClassLoaders(), name);
195218
}
196219

197220
@Override
198221
protected Enumeration<URL> findResources(String name) throws IOException {
199-
return findResources(getActiveClassLoader(), name);
222+
List<ClassLoader> activeClassLoaders = getActiveClassLoaders();
223+
assert !activeClassLoaders.isEmpty() & activeClassLoaders.size() <= 2;
224+
ClassLoader activeClassLoader = activeClassLoaders.get(0);
225+
ClassLoader activeClassLoaderParent = activeClassLoaders.size() > 1 ? activeClassLoaders.get(1) : null;
226+
if (activeClassLoaderParent != null) {
227+
return newCompoundEnumeration(findResources(activeClassLoaderParent, name), findResources(activeClassLoader, name));
228+
}
229+
return findResources(activeClassLoader, name);
230+
}
231+
232+
@SuppressWarnings("unchecked")
233+
private static <T> Enumeration<T> newCompoundEnumeration(Enumeration<?>... enums) {
234+
try {
235+
return (Enumeration<T>) compoundEnumerationConstructor.newInstance((Object) enums);
236+
} catch (ReflectiveOperationException e) {
237+
throw VMError.shouldNotReachHere("Cannot instantiate CompoundEnumeration", e);
238+
}
200239
}
201240

202241
public Class<?> forNameOrNull(String name, boolean initialize) {
203242
try {
204-
return Class.forName(name, initialize, getActiveClassLoader());
243+
return Class.forName(name, initialize, getActiveClassLoaders().get(0));
205244
} catch (LinkageError | ClassNotFoundException ignored) {
206245
return null;
207246
}
@@ -212,7 +251,7 @@ public Class<?> predefineClass(String name, byte[] array, int offset, int length
212251
if (forNameOrNull(name, false) != null) {
213252
throw VMError.shouldNotReachHere("The class loader hierarchy already provides a class with the same name as the class submitted for predefinition: " + name);
214253
}
215-
return defineClass(getActiveClassLoader(), name, array, offset, length);
254+
return defineClass(getActiveClassLoaders().get(0), name, array, offset, length);
216255
}
217256

218257
@Override
@@ -224,11 +263,18 @@ public String toString() {
224263
'}';
225264
}
226265

227-
private ClassLoader getActiveClassLoader() {
228-
ClassLoader delegate = nativeImageClassLoader;
229-
return delegate != null
230-
? delegate
231-
: defaultSystemClassLoader;
266+
private List<ClassLoader> getActiveClassLoaders() {
267+
ClassLoader activeClassLoader = nativeImageClassLoader;
268+
if (activeClassLoader != null) {
269+
ClassLoader activeClassLoaderParent = activeClassLoader.getParent();
270+
if (activeClassLoaderParent instanceof NativeImageClassLoaderSupport.ClassPathClassLoader) {
271+
return List.of(activeClassLoader, activeClassLoaderParent);
272+
} else {
273+
return List.of(activeClassLoader);
274+
}
275+
} else {
276+
return List.of(defaultSystemClassLoader);
277+
}
232278
}
233279

234280
/**

0 commit comments

Comments
 (0)