EVALUATION
A related issue is the confusion around where the delegation is supposed to happen. For example, code like this (taken from FactoryFinder line 81:
if (cl == null) {
// If classloader is null Use the bootstrap ClassLoader.
// Thus Class.forName(String) will use the current
// ClassLoader which will be the bootstrap ClassLoader.
providerClass = Class.forName(className);
} else {
try {
providerClass = cl.loadClass(className);
} catch (ClassNotFoundException x) {
if (doFallback) {
// Fall back to current classloader
cl = FactoryFinder.class.getClassLoader();
providerClass = cl.loadClass(className);
} else {
throw x;
}
}
}
assumes that when the context classloader is null, it uses the bootstrap classloader (since Class.forName uses the caller's classloader, which is bootstrap loader.) Yet in some other places, such as in SecuritySupport (line 77)
InputStream getResourceAsStream(final ClassLoader cl,
final String name)
{
return (InputStream)
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
InputStream ris;
if (cl == null) {
ris = ClassLoader.getSystemResourceAsStream(name);
} else {
ris = cl.getResourceAsStream(name);
}
return ris;
}
});
}
... it delegates to the system classloader. So if my context classloader is null, JAXP may find META-INF/services from my system classloader, yet it will fail to load it from the bootstrap classloader (as the implementation was in my system classpath, not bootstrap.)
|