UPDATE 1: Indeed, the URL format differences cause the error. Here is a unit test (cut and obfuscated by hand; hope I didn't miss anything) showing the problem:
@Test
public void wheresWaldo2() throws ClassNotFoundException, IllegalAccessException, InstantiationException, IOException, NoSuchMethodException {
// Find Waldo from file:/someLocation/waldo.jar. Prove that works.
URL waldosJar = new File("/someLocation/waldo.jar").toURI().toURL();
assertNotNull(waldosJar);
assertEquals("file", waldosJar.getProtocol());
String waldosPath = waldosJar.getPath();
assertNotNull(waldosPath);
assertTrue(waldosPath.endsWith("/waldo.jar"));
ClassLoader cl = new URLClassLoader(new URL[] { waldosJar }, this.getClass().getClassLoader());
Class<?> waldosClass = cl.loadClass("com.foobar.Waldo");
assertNotNull(waldosClass);
assertEquals("com.foobar.Waldo", waldosClass.getName());
assertSame(cl, waldosClass.getClassLoader());
Class<?> jimbosClass = cl.loadClass("com.foobar.Jimbo"); // Note: works
assertNotNull(jimbosClass);
// Find Waldo from jar:file:/someLocation/waldo.jar!/. Prove that works.
// This URL, when passed to a URLClassLoader, should result in the same
// functionality as the first one. But it doesn't.
waldosJar = new URL("jar:" + waldosJar.toExternalForm() + "!/");
assertEquals("jar", waldosJar.getProtocol());
assertEquals("file:" + waldosPath + "!/", waldosJar.getPath());
cl = new URLClassLoader(new URL[] { waldosJar }, this.getClass().getClassLoader());
waldosClass = cl.loadClass("com.foobar.Waldo");
assertNotNull(waldosClass);
assertEquals("com.foobar.Waldo", waldosClass.getName());
assertSame(cl, waldosClass.getClassLoader());
jimbosClass = cl.loadClass("com.foobar.Jimbo"); // XXX FAILS
}
UPDATE 0: The problem may have to do with the supposed, but not actual, equivalence between two URL
s referring to a jar file. For example, the following two URLs are supposed to refer to the same file:
file:/myjar.jar
jar:file:/myjar.jar!/
When I pass a URL built from the first format to my machinery, I think things are working. When I pass a URL built from the second format, I get the results described below. I am testing more to confirm all this beyond a doubt.
ORIGINAL QUESTION
(I am aware of this question .)
I have a jar file, waldo.jar
, that contains a META-INF/MANIFEST.MF
that looks like this:
Manifest-Version: 1.0
Class-Path: jimbo.jar
It also has a class at the following location within it:
com/foobar/Waldo.class
The class' source code is essentially:
package com.foobar;
public class Waldo {
public Jimbo getJimbo() {
return null;
}
}
Next, in the same directory, I have a jar file, jimbo.jar
, that contains a class at the following location within it:
com/foobar/Jimbo.class
That class' source code is essentially:
package com.foobar;
public class Jimbo {
}
Now I construct a URLClassLoader
with a URL to waldo.jar
. To review: jimbo.jar
contains Jimbo
and is "next to" waldo.jar
, and is listed in waldo.jar
's META-INF/MANIFEST-MF
's Class-Path
header appropriately. waldo.jar
contains Waldo
, that has a code reference to Jimbo
. With me so far?
I can load com.foobar.Waldo
just fine. But if I do something with Waldo
that involves com.foobar.Jimbo
, like, for example, calling Waldo.class.getDeclaredMethod("getJimbo")
, I get a NoClassDefFoundError
. Here is a sample stack:
java.lang.NoClassDefFoundError: com/foobar/Jimbo
at java.lang.Class.getDeclaredMethods0(Native Method)
at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
at java.lang.Class.getDeclaredMethod(Class.java:2128)
at com.foobar.TestClassLoadingProblems.wheresWaldo(TestClassLoadingProblems.java:115)
Caused by:
java.lang.ClassNotFoundException: com.foobar.Jimbo
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at com.foobar.MyClassLoader.findClass(...) // calls super.findClass()
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
This suggests to me that URLClassLoader
is not consulting the Class-Path
header properly in all cases (I'm aware of how it works in general ).
Can anyone shed light on what is happening here?
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.