javajsonjar

Java: NoClassDefFoundError: org/json/JSONException


So, I've spent the whole day with this problem.
I'm sure, that I'm using correct classpath.
Also, I have other packages as dependences, and they work perfectly.

I have a class that uses org.json.*
Also there are some other outer packages used in this class.
All this dependences are placed as jar files in my /path/to/libs/.
json-20160212.jar is among them.

I'm compiling my sources with

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

Compilation goes without issues.
Then, I'm creating jar from my class-files.
Manifest:

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

Command line:
jar cfm output.jar manifest -C dst/ ./com

I'm getting jar with this manifest:

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

As I've understood, this is ok for compiled manifest to have splitted lines.

Now, I'm running my app from command line and get this error:

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

As I know, that means, that org.json.JSONException was ok at compile time but missing at run time.
But what must I do with this info?
I have that file. It was at its place during compilation and at runtime.
Also there are other dependences, and their jars are also at that place.

If I remove JSON usage from my app, everything is working ok.
So, I can make conclusion, that it is the package org.json itself, that makes the problem.

What must I do, to make it work?

UPDATE

Now, I've made this changes:

My directory structure:

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

Manifest:

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

Compilation:

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

I'm getting jar with the structure as excepted:

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

And I'm running it with java -jar dst/output.jar.
Result is the same: java.lang.NoClassDefFoundError: org/json/JSONException


Solution

  • So, the solution:

    As I've understand, the only way to access the content of the jar files that are inside your jar, is to write your own class loader.
    Without it, jar files must be extracted and that extracted content must be included to output.jar.