繁体   English   中英

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

[英]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.jarjimbo.jar包含Jimbo并且是jimbo.jar “下一个”,并waldo.jarwaldo.jarMETA-INF/MANIFEST-MFClass-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标头(我知道它通常如何工作的 )。

任何人都可以了解这里发生的事情吗?

这是由于JDK中错误所致。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM