[英]Does URLClassLoader traverse MANIFEST.MF Class-Path headers properly?
更新1:確實,URL格式的差異會導致錯誤。 這是一個顯示問題的單元測試(手工剪切和混淆;希望我什么都沒錯過):
@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
}
更新0:問題可能與兩個引用jar文件的URL
之間的假定等效性有關,而不與實際等效性有關。 例如,以下兩個URL應該引用同一文件:
file:/myjar.jar
jar:file:/myjar.jar!/
當我將從第一種格式構建的URL傳遞給我的機器時,我認為一切正常。 當我傳遞從第二種格式構建的URL時,得到以下描述的結果。 我正在做更多的測試以證實所有這些。
原始問題
(我知道這個問題 。)
我有一個jar文件waldo.jar
,其中包含如下所示的META-INF/MANIFEST.MF
:
Manifest-Version: 1.0
Class-Path: jimbo.jar
它還在其中的以下位置有一個類:
com/foobar/Waldo.class
該類的源代碼本質上是:
package com.foobar;
public class Waldo {
public Jimbo getJimbo() {
return null;
}
}
接下來,在同一目錄中,我有一個jar文件jimbo.jar
,該文件在其中的以下位置包含一個類:
com/foobar/Jimbo.class
該類的源代碼本質上是:
package com.foobar;
public class Jimbo {
}
現在,我構造一個URLClassLoader
其中包含指向waldo.jar
的URL。 回顧jimbo.jar
: jimbo.jar
包含Jimbo
並且是jimbo.jar
“下一個”,並waldo.jar
在waldo.jar
的META-INF/MANIFEST-MF
的Class-Path
標頭中列出。 waldo.jar
包含Waldo
,該代碼具有對Jimbo
的代碼引用。 到目前為止和我在一起?
我可以加載com.foobar.Waldo
很好。 但是,如果我對Waldo
做一些涉及com.foobar.Jimbo
,例如調用Waldo.class.getDeclaredMethod("getJimbo")
, 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
在所有情況下都沒有正確地查詢Class-Path
標頭(我知道它通常是如何工作的 )。
任何人都可以了解這里發生的事情嗎?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.