Java URLClassLoader是否正确遍历MANIFEST.MF类路径头?

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

更新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
}
它在其中的以下位置也有一个类:

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中添加条目(文件结构的索引)就可以了。嗨,不,这当然不是问题所在。不过,谢谢你的评论。