2016-04-26 2 views
0

私はこの問題で一日中過ごしました。
私は正しいクラスパスを使用していると確信しています。
また、他のパッケージも依存関係にあり、完全に動作します。Java:NoClassDefFoundError:org/json/JSONException

私はorg.jsonを使用するクラスを持っています*
また、このクラスで使用されるいくつかの外部パッケージがあります。
この依存関係はすべて、my/path/to/libs /にjarファイルとして格納されます。
json-20160212.jarがその中にあります。

私は

javac \ 
    -cp "src/:/path/to/libs/json-20160212.jar:/path/to/libs/other.jar:/path/to/libs/another.jar" \ 
    -d dst/ \ 
    src/com/example/Source.java 

コンパイルは問題なく行くと私のソースをコンパイルしています。
次に、クラスファイルからjarファイルを作成しています。
マニフェスト:

Main-Class: com.example.Source 
Class-Path: /path/to/libs/json-20160212.jar 
    /path/to/libs/other.jar 
    /path/to/libs/another.jar 

コマンドライン:
jar cfm output.jar manifest -C dst/ ./com

私はこのマニフェストでjarファイルになっています:へのマニフェストコンパイルのために私は理解してきたように

Manifest-Version: 1.0 
Class-Path: /path/to/libs/json-20160212.jar /path/to/libs/other.jar /p 
ath/to/libs/another.jar 
Created-By: 1.7.0_101 (Oracle Corporation) 
Main-Class: com.example.Source 

は、これはokです分割線があります。今

、私はコマンドラインから私のアプリを実行すると、このエラーを取得しています:

Exception in thread "Thread-0" java.lang.NoClassDefFoundError: org/json/JSONException 
    at com.example.Source.run(Source.java:30) 
Caused by: java.lang.ClassNotFoundException: org.json.JSONException 
    at java.net.URLClassLoader$1.run(URLClassLoader.java:366) 
    at java.net.URLClassLoader$1.run(URLClassLoader.java:355) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at java.net.URLClassLoader.findClass(URLClassLoader.java:354) 
    at java.lang.ClassLoader.loadClass(ClassLoader.java:425) 
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308) 
    at java.lang.ClassLoader.loadClass(ClassLoader.java:358) 
    ... 1 more 

私が知っているように、それは意味し、org.json.JSONExceptionは、コンパイル時にOKが、実行時に欠落していました。
この情報はどうすればよいですか?
私はそのファイルを持っています。コンパイル中と実行時に、その場所にありました。
また、他の依存関係もあり、その瓶もその場所にあります。

アプリからJSONの使用状況を削除すると、すべて正常に機能しています。
したがって、私は結論を下すことができます。パッケージorg.json自体であり、問​​題を引き起こします。

私はそれを機能させるために何をしなければなりませんか?

私のディレクトリ構造を:

libs/ 
    json-20160212.jar 
    other.jar 
    another.jar 
src/ 
    com/ 
     example/ 
      Source.java 
dst/ 

マニフェスト:さて、私はこれが変わる作った

UPDATE

Main-Class: com.example.Source 
Class-Path: libs/json-20160212.jar 
    libs/other.jar 
    libs/another.jar 

編集:

javac \ 
    -cp "src/:libs/json-20160212.jar:libs/other.jar:libs/another.jar" \ 
    -d dst/ \ 
    src/com/example/Source.java 

Jarchiving:

jar cfm dst/output.jar manifest -C dst/ ./com ./libs 

私は除外されるような構造でjarファイルを取得しています:

META-INF/ 
META-INF/MANIFEST.MF 
com/ 
com/example/ 
com/example/Source.class 
libs/ 
libs/json-20160212.jar 
libs/other.jar 
libs/another.jar 

そして私はjava -jar dst/output.jarでそれを実行していますよ。
結果は同じです:java.lang.NoClassDefFoundError: org/json/JSONException

+0

結果のjarファイルの内容を確認してください。 JSON jarは実際には/path/to/libs/json-20160212.jarにありますか? – ManoDestra

+0

私はあなたのプロジェクトに特定のlibを追加していないと思います。それを確認し、必要なすべてのjarファイルがすべてプロジェクトに正しく含まれていることを確認してください。 –

+0

上記のjarコマンド( 'jar cfm output.jar manifest -C dst /。/ com')を実行すると、ライブラリの依存関係をjarファイルに追加していないように見えます。あなたのクラスだけでなく、パス/ to/libも含めてください。それ以降はうまくいくはずです。 – ManoDestra

答えて

0

ので、解決策:

私が理解してきたように、あなたのjarファイル内にあるjarファイルのコンテンツにアクセスする唯一の方法は、独自のクラスローダを書くことです。
jarファイルがない場合、jarファイルを抽出し、抽出されたコンテンツをoutput.jarに含める必要があります。

+0

これを行う必要はありません(私は以前に、私は既に正しく参照された別のjarを含むJARを作ったといい、うまくいきました)、確かにsbt-assembly(私はこれを仕事で使っています)やOneJarなど、これを行うためのツールがあります。彼らは決定メカニズムを使用してクラスの競合に対処し、すべてのクラスを依存するjarから単一のfat jarに展開します。ファット・ジャー・ソリューションに関するいくつかのアドバイスで私の答えを更新しました。 – ManoDestra

+1

私はあなたのjarを実行することができたと思います。なぜなら、あなたのjarファイル内のファイル構造はあなたのプロジェクトディレクトリと同じだからです。したがって、あなたのライブラリ(依存関係 - jars)はjarファイルからではなく、あなたのローカルファイルシステムから取得されました。結果のjarを独立した場所に移動して実行してください。 – seelts

+0

さらに、http://docs.oracle.com/javase/tutorial/deployment/jar/downman.htmlの公式ドキュメントを参照してください。最初の注記:「Class-Pathヘッダーは、ローカルネットワーク上のクラスまたはJARファイルを指し、JARファイル内のJARファイルまたはインターネットプロトコル上でアクセス可能なクラスを指します。JARファイル内のクラスをクラスパスにロードするにはそれらのクラスをロードするカスタムコードを記述する必要があります。とにかく、ありがとう!あなたの答えは私に解決の方向性を与えました。 – seelts

1

問題は実行時クラスパスです。このエラーには魔法はありません。これは、org.json.JSONExceptionが実行時クラスパス上にないことを意味します。このクラスを持つjarファイルを見つけて、ランタイムクラスパスに配置します。

実行時に必要なjars /クラスは、コンパイルに必要なjars /クラスと必ずしも同じではありません。コンパイル時のクラスパスよりも実行時のクラスパスでもっと多くのことが必要になることがよくあります。コンパイルしているコードでJSONExceptionを明示的に使用しないと、クラスパスをコンパイルする必要はありません。しかし、コードへの依存関係の1つがJSONExceptionを必要とし、実行時クラスパスにない場合、NoClassDefFoundErrorが返されます。

その他の問題が発生する可能性があることは、クラスパスに2つの異なるバージョンのjson jarがあることです。通常、クラスパスのクラスの最初のバージョンがロードされ、もう1つは無視されます。最初のjarに必要なJSONExceptionのバージョン/署名がないのに2番目のJSONExceptionがあった場合は、クラスパス上にあるため、正しいクラスが無視されます。

1

問題は、結果のjarに依存jarを追加していないように見えます。

私は、このjarファイルを作成するには... ...次の構造(ジャーTFを使用してチェックする)と、

Main-Class: BeanIt
Class-Path: lib/opencsv-3.7.jar lib/commons-lang3-3.4.jar

META-INF/
META-INF/MANIFEST.MF
BeanIt.class
TestBean.class
lib/
lib/opencsv-3.7.jar
lib/commons-lang3-3.4.jar

私のマニフェストを同様の試験ジャーを作成している

このようなコマンドを実行する必要があります。

jar cfm App.jar MANIFEST.MF BeanIt.class TestBean.class lib 

私はlib foldeを追加したことがわかりますrをjarファイルに追加し、マニフェスト内のclasspathの内容を参照します。

このように、既存のlibを更新することができます...

jar uf App.jar path 

ここで、pathは、path/to/libディレクトリのルートパスです。そしてそれはあなたの瓶にそれを単に加えるだけです。

最初にjar tfを使用してjarを確認して、その内容を確認できます。

それでも問題が解決しない場合は、すべての内部jarsクラスを展開し、すべての必要なクラスを含む単一のJARにすべて展開する「FAT JAR」ソリューションを参照できます。彼らは、さまざまなJARのクラスの競合に対処するための決定メカニズムを使用します。 sbt-assemblyまたはOneJarなどのツールは、JARを期待通りに動作させることができない場合は、ここで必要なものになる可能性があります。

+0

オリジナルの投稿を更新しました。それを見てください。 – seelts

+0

json-20160212.jarに必要なクラス(org.json.JSONException)が確実にありますか?代わりにJSONExceptionが発生した場合に備えて、JSONExceptionのケーシングをダブルチェックしてください。そのクラスがあなたのjson jarにある限り、json jarはJarファイル内にあり、マニフェストを介してclasspathに参照され、あなたの呼び出しクラスから正しく参照されます。おそらく、他の瓶からクラスを呼び出すことができるかどうかをチェックします。それが大丈夫なら、おそらく大文字と小文字を区別する問題か、クラスの問題がありません。 – ManoDestra

+0

私の答えを見てください:http://stackoverflow.com/a/36886634/858602 – seelts