2016-04-26 109 views
0

所以,我花了整整一天的时间解决了这个问题。
我敢肯定,我正在使用正确的类路径。
另外,我还有其他软件包作为依赖,并且它们完美地工作。Java:NoClassDefFoundError:org/json/JSONException

我有一个使用org.json的类。*
另外还有一些其他的外层包在这个类中使用。
所有这些依赖关系都放在我的/ 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

我得到罐子这个清单:

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 

正如我的理解,这是确定的编译舱单有分裂线。

现在,我从命令行运行我的应用程序,并得到这个错误:

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是在编译时确定,但在运行时失踪。
但是,我必须用这个信息做什么?
我有那个文件。它在编译期间和运行时处于它的位置。
还有其他的依赖,他们的罐子也在那个地方。

如果我从我的应用程序中删除JSON用法,一切工作正常。
所以,我可以得出结论,它是包org.json本身,这使得问题。

我该做些什么才能使其工作?

UPDATE

现在,我做了这样的变化:

我的目录结构:

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

清单:

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 

我越来越罐子结构为例外:

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实际位于jar中的/path/to/libs/json-20160212.jar上吗? – ManoDestra

+0

我认为你没有在你的项目中添加特定的lib。检查它并确保项目中包含的所有必需的罐子都正确。 –

+0

通过上面的jar命令('jar cfm output.jar清单-C dst /。/ com'),看起来你不会将库依赖项添加到你的jar中。包括路径/到/ lib以及你的类,它应该在那之后正常工作。 – ManoDestra

回答

0

所以,解决方法:

正如我明白了,访问是你的罐子里面的jar文件的内容的唯一方法,就是写自己的类加载器。
没有它,必须提取jar文件,并且提取的内容必须包含在output.jar中。

+0

你不应该这样做(正如我前面所说,我已经做了一个JAR包含另一个jar,引用正确,它运行良好),但肯定有一些工具可以让你做到这一点,例如sbt-assembly(我使用这个工作)和OneJar。他们使用决策机制来处理阶级冲突,并将所有从依赖瓶子的类扩展到单个胖罐子中。更新我的答案,并提供一些有关胖罐解决方案的进一步建议 – ManoDestra

+1

我想,你能够运行你的jar,因为你的jar里面的文件结构与你的项目目录中的相同。所以你的libs(依赖jar)不是从jar里取的,而是从你的本地文件系统中取得的。尝试将结果jar移动到独立位置并运行它。 – seelts

+0

另外,请查看官方文档:http://docs.oracle.com/javase/tutorial/deployment/jar/downman.html。第一个注意:“Class-Path头指向本地网络上的类或JAR文件,而不是JAR文件中的JAR文件或通过Internet协议访问的类。将JAR文件中的JAR文件中的类加载到类路径中,您必须编写自定义代码来加载这些类。“无论如何,非常感谢!你的回答给了我解决方案的方向。 – seelts

1

问题是你的运行时类路径。这个错误没有魔法。这很简单,意味着org.json.JSONException不在你的运行时类路径上。找到有这个类的jar,并把它放到你的运行时类路径中。

请注意,运行时所需的jar /类不一定与编译所需的jar/classes相同。在运行时类路径中,您经常需要比编译类路径更多的东西。如果在编译的代码中没有明确使用JSONException,那么它就不必在编译类路径中。但是,如果您的代码的其中一个依赖项需要JSONException,并且它不在您的运行时类路径中,您将得到一个NoClassDefFoundError。

另一个可能发生的问题是您的classpath上有2个不同版本的json jar。通常,类路径上的类的第一个版本被加载,而另一个被忽略。如果第一个jar没有你需要的JSONException的版本/签名,但是第二个没有,那么正确的类仍然会被忽略,因为它在类路径上更靠后。

1

这个问题似乎是你没有添加依赖瓶到你的生成jar。

我创建了一个类似的试验瓶,具有下列结构(使用的jar TF检查)...

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

我的清单...

Main-Class: BeanIt
Class-Path: 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并在清单中的类路径中引用其内容。

所以,你可以更新你现有的库,像这样...

jar uf App.jar path 

其中path是路径/到/ lib目录的根路径。它会简单地添加到你的jar。

您可以先使用jar tf检查您的罐子,看看它包含什么。

如果你仍然难以正常工作,那么你可以看看一个“FAT JAR”解决方案,从而展开所有内部的jar类,并将它们全部展平为包含所有必需类的单个JAR。他们使用决策机制来处理不同JAR中的类别冲突。诸如sbt-assemblyOneJar之类的工具可能是您在这里需要的,如果您无法让您的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