UPDATE 1:実際、URL形式の違いによりエラーが発生します。ここではユニットテスト(カット、手で難読化され、私は何かを逃さなかった願っています)で、問題を示す:URLClassLoaderはMANIFEST.MFクラスパスヘッダーを正しくトラバースしますか?
@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:は、問題が想定さとしなければならないが、実際のないことがあり、 jarファイルを参照する2つの間の等価。私は機械に最初の形式から構築されたURLを渡すとき、私は物事を考える
file:/myjar.jar
jar:file:/myjar.jar!/
:たとえば、次の2つのURLが同じファイルを参照することになっています作業しています。私が第2フォーマットから構築したURLを渡すと、私は以下の結果を得ます。私は疑問の余地なくこれをすべて確認するためにさらにテストしています。
元の質問
(私はthis questionの認識しています。)
私はこのようになりますMETA-INF/MANIFEST.MF
が含まれているjarファイル、waldo.jar
、持っている:
Manifest-Version: 1.0
Class-Path: jimbo.jar
をまた、その中の次の場所にクラスがあります。
com/foobar/Waldo.class
クラスのソースコードは、基本的に次のとおりです。
com/foobar/Jimbo.class
:
package com.foobar;
public class Waldo {
public Jimbo getJimbo() {
return null;
}
}
次に、同じディレクトリに、私はその中に次の場所にクラスが含まれているjarファイル、jimbo.jar
を、持っています
そのクラスのソースコードは、基本的に次のとおりです。
package com.foobar;
public class Jimbo {
}
今私はURLClassLoader
を構築しますURLはwaldo.jar
になります。レビューするには:jimbo.jar
はJimbo
を含み、 "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")
と呼ぶのと同じように、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
は(私はhow it works in generalの承知している)すべての場合に適切にClass-Path
ヘッダーに相談されていないことを私に示唆しています。
ここで何が起こっているのか誰にも光を当てはめることができますか?
'Waldo.class.getDeclaredMethod(" getJimbo ")'の代わりに 'new Jimbo()'を試してみると、結果はどうなりますか? –
クラスローダーを使っているクラスは 'ジンボ'について知らないので、私は 'new Jimbo()'を実行できません。 'jimbosClass.newInstance()'はほとんど確実に失敗します。私はそれを調べるために私のテストを再加速します。しかし、調整しておいてください。問題は 'URLClassLoader'に提供されたURLフォーマットであるようです:' jar:file:/myjar.jar!/ 'の代わりに' file:/ myjar.jar'を使用すると(同等であると思われます)すべてが機能するように見えます。 –
私はこの瓶が手動で生成されると思います。そのクラスを含むフォルダのエントリがありません。 jarファイルにエントリ(ファイル構造のインデックスの種類)を追加するだけで動作します。 – user1615664