[英]Does URLClassLoader traverse MANIFEST.MF Class-Path headers properly?
UPDATE 1: Indeed, the URL format differences cause the error. 更新1:确实,URL格式的差异会导致错误。 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. 更新0:问题可能与两个引用jar文件的URL
之间的假定等效性有关,而不与实际等效性有关。 For example, the following two URLs are supposed to refer to the same file: 例如,以下两个URL应该引用同一文件:
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. 当我将从第一种格式构建的URL传递给我的机器时,我认为一切正常。 When I pass a URL built from the second format, I get the results described below. 当我传递从第二种格式构建的URL时,得到以下描述的结果。 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: 我有一个jar文件waldo.jar
,其中包含如下所示的META-INF/MANIFEST.MF
:
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: 接下来,在同一目录中,我有一个jar文件jimbo.jar
,该文件在其中的以下位置包含一个类:
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
. 现在,我构造一个URLClassLoader
其中包含指向waldo.jar
的URL。 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. 回顾jimbo.jar
: jimbo.jar
包含Jimbo
并且是jimbo.jar
“下一个”,并waldo.jar
在waldo.jar
的META-INF/MANIFEST-MF
的Class-Path
标头中列出。 waldo.jar
contains Waldo
, that has a code reference to Jimbo
. waldo.jar
包含Waldo
,该代码具有对Jimbo
的代码引用。 With me so far? 到目前为止和我在一起?
I can load com.foobar.Waldo
just fine. 我可以加载com.foobar.Waldo
很好。 But if I do something with Waldo
that involves com.foobar.Jimbo
, like, for example, calling Waldo.class.getDeclaredMethod("getJimbo")
, I get a NoClassDefFoundError
. 但是,如果我对Waldo
做一些涉及com.foobar.Jimbo
,例如调用Waldo.class.getDeclaredMethod("getJimbo")
, Waldo.class.getDeclaredMethod("getJimbo")
收到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 ). 这向我表明, URLClassLoader
在所有情况下都没有正确地查询Class-Path
标头(我知道它通常是如何工作的 )。
Can anyone shed light on what is happening here? 任何人都可以了解这里发生的事情吗?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.