URLClassLoader 是否正确遍历 MANIFEST.MF Class-Path headers?
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 时,我得到如下所述的结果。我正在测试更多以毫无疑问地证实这一切。
原始问题
(我知道 this question。)
我有一个 jar 文件 waldo.jar
,其中包含一个 META-INF/MANIFEST.MF
,如下所示:
Manifest-Version: 1.0
Class-Path: jimbo.jar
它在以下位置也有一个 class:
com/foobar/Waldo.class
class' 源代码本质上是:
package com.foobar;
public class Waldo {
public Jimbo getJimbo() {
return null;
}
}
接下来,在同一目录中,我有一个 jar 文件 jimbo.jar
,其中在以下位置包含一个 class:
com/foobar/Jimbo.class
那个class'源代码本质上是:
package com.foobar;
public class Jimbo {
}
现在我构造了一个URLClassLoader
和一个URL到waldo.jar
。回顾一下:jimbo.jar
包含 Jimbo
并且是 "next to" waldo.jar
,并且列在 waldo.jar
的 META-INF/MANIFEST-MF
的 Class-Path
中header 适当。 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
在所有情况下都没有正确咨询 Class-Path
header(我知道 how it works in general)。
任何人都可以阐明这里发生的事情吗?
这是由于bug in the JDK。
更新 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 时,我得到如下所述的结果。我正在测试更多以毫无疑问地证实这一切。
原始问题
(我知道 this question。)
我有一个 jar 文件 waldo.jar
,其中包含一个 META-INF/MANIFEST.MF
,如下所示:
Manifest-Version: 1.0
Class-Path: jimbo.jar
它在以下位置也有一个 class:
com/foobar/Waldo.class
class' 源代码本质上是:
package com.foobar;
public class Waldo {
public Jimbo getJimbo() {
return null;
}
}
接下来,在同一目录中,我有一个 jar 文件 jimbo.jar
,其中在以下位置包含一个 class:
com/foobar/Jimbo.class
那个class'源代码本质上是:
package com.foobar;
public class Jimbo {
}
现在我构造了一个URLClassLoader
和一个URL到waldo.jar
。回顾一下:jimbo.jar
包含 Jimbo
并且是 "next to" waldo.jar
,并且列在 waldo.jar
的 META-INF/MANIFEST-MF
的 Class-Path
中header 适当。 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
在所有情况下都没有正确咨询 Class-Path
header(我知道 how it works in general)。
任何人都可以阐明这里发生的事情吗?
这是由于bug in the JDK。