Java URLClassLoader是否正确遍历MANIFEST.MF类路径头?
更新1:确实,URL格式的差异导致了错误。下面是一个单元测试(手工剪切和模糊处理;希望我没有遗漏任何内容),它显示了问题:Java URLClassLoader是否正确遍历MANIFEST.MF类路径头?,java,urlclassloader,Java,Urlclassloader,更新1:确实,URL格式的差异导致了错误。下面是一个单元测试(手工剪切和模糊处理;希望我没有遗漏任何内容),它显示了问题: @Test public void wheresWaldo2() throws ClassNotFoundException, IllegalAccessException, InstantiationException, IOException, NoSuchMethodException { // Find Waldo from file:/someLocation
@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
}
它在其中的以下位置也有一个类:
com/foobar/Waldo.class
com/foobar/Jimbo.class
该类的源代码基本上是:
package com.foobar;
public class Waldo {
public Jimbo getJimbo() {
return null;
}
}
package com.foobar;
public class Jimbo {
}
接下来,在同一个目录中,我有一个jar文件,jimbo.jar
,其中包含一个位于以下位置的类:
com/foobar/Waldo.class
com/foobar/Jimbo.class
该类的源代码基本上是:
package com.foobar;
public class Waldo {
public Jimbo getJimbo() {
return null;
}
}
package com.foobar;
public class Jimbo {
}
现在,我构造了一个URLClassLoader
,其URL指向waldo.jar
。要查看:jimbo.jar
包含jimbo
,并且是“紧挨着”waldo.jar
,并且被列在waldo.jar
的META-INF/MANIFEST-MF
的类路径
头中waldo.jar
包含waldo
,它有一个对Jimbo
的代码引用。到目前为止和我在一起
我可以加载com.foobar.Waldo
很好。但是如果我使用Waldo
做一些涉及com.foobar.Jimbo
的事情,比如调用Waldo.class.getDeclaredMethod(“getJimbo”)
,我会得到一个NoClassDefFoundError
。下面是一个示例堆栈:
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)
这向我表明,URLClassLoader
在所有情况下都没有正确地查阅类路径
头(我知道)
有人能解释一下这里发生了什么吗?这是由于a。这是由于a。如果不是
Waldo.class.getDeclaredMethod(“getJimbo”)
你只需尝试new Jimbo()
,结果是什么?我当然不能做new Jimbo()
,因为使用类加载器的类不知道关于Jimbo
jimbosClass.newInstance()
几乎肯定会失败。我将重新调整我的测试以检查它。不过,请继续关注;问题似乎在于提供给URLClassLoader
的URL格式:如果我使用file:/myjar.jar
而不是jar:file:/myjar.jar/代码>(它们应该是等价的),一切看起来都正常。好的,我认为这个jar是手动生成的。您缺少包含所属类的文件夹的条目。只要在jar中添加条目(文件结构的索引)就可以了。嗨,不,这当然不是问题所在。不过,谢谢你的评论。如果你不使用Waldo.class.getDeclaredMethod(“getJimbo”)
而只是尝试newJimbo()
,结果会是什么?我当然不能做newJimbo()
,因为使用类加载器的类不知道Jimbo
jimbosClass.newInstance()
几乎肯定会失败。我将重新调整我的测试以检查它。不过,请继续关注;问题似乎在于提供给URLClassLoader
的URL格式:如果我使用file:/myjar.jar
而不是jar:file:/myjar.jar/代码>(它们应该是等价的),一切看起来都正常。好的,我认为这个jar是手动生成的。您缺少包含所属类的文件夹的条目。只要在jar中添加条目(文件结构的索引)就可以了。嗨,不,这当然不是问题所在。不过,谢谢你的评论。