Skip to content

Commit 3ca818d

Browse files
committed
Make NativeImageSystemClassLoader able to handle having module classloader with a parent ClassPathClassLoader
1 parent 2a328fa commit 3ca818d

File tree

2 files changed

+82
-29
lines changed

2 files changed

+82
-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+
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: 75 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,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

Comments
 (0)