从Scala文件创建可执行jar包出现问题

4

我想使用IntelliJ 9.0将我的项目导出为jar文件。我的项目在Intellij中编译和运行都没有问题,但是当我将它写入.jar文件并打开它时,会显示错误。

我的主类大致如下:

package Main

//Imports

object Main{
  def main(args: Array[String]) {
    println("Main: Hello, world!")
    //do stuff
}

现在,在工件窗口中,我创建了一个包含以下内容的.jar文件:
  1. 主类:Main.Main
  2. 类路径:lib/javacsv lib/scala-compiler.jar lib/scala-library.jar lib/scalatest-1.0-test.jar lib/scalatest-1.0.jar lib/tools.jar lib/jtds-1.2.2.jar lib/flex-messaging-common.jar lib/flex-messaging-core.jar lib/spring.jar lib/mysql-connector-java-5.1.7-bin.jar lib/ojdbc14.jar lib/commons-logging.jar lib/postgresql-8.4-701.jdbc3.jar lib/log4j-1.2.15.jar lib/poi-3.6-20091214.jar lib/poi-ooxml-3.6-20091214.jar lib/dom4j-1.6.1.jar lib/poi-ooxml-schemas-3.6-20091214.jar lib/geronimo-stax-api_1.0_spec-1.0.jar lib/xmlbeans-2.3.0.jar lib/rt.jar lib/ifxjdbc.jar lib/db2jcc4.jar

我已经仔细检查了所有这些类是否都在项目中,并且是唯一的类。需要注意的是,它包括lib/scala-compiler.jarlib/scala-library.jar

构建项目:java -jar myScalaApp.jar,我得到:

Exception in thread "main" java.lang.NoClassDefFoundError: scala/ScalaObject
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:675)
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:124)
    at java.net.URLClassLoader.defineClass(URLClassLoader.java:260)
    at java.net.URLClassLoader.access$000(URLClassLoader.java:56)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:195)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:316)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:288)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
    at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:374)
    at Main.Main.main(Main.scala)
Caused by: java.lang.ClassNotFoundException: scala.ScalaObject
    at java.net.URLClassLoader$1.run(URLClassLoader.java:200)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:316)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:288)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
    at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:374)
    ... 13 more

我知道它找不到scala类,但我确保它们在那里。还可能有什么问题,我该如何解决?

2个回答

5
我觉得可能有两种情况导致了问题:
  • scala-library.jar 不在你的jar包内;
  • 运行时的类路径没有包含 scala-library.jar
我不知道IntelliJ如何构建你的jar包: 它是将所有库文件解压并与你的代码一起混合成一个大的jar包,还是将库文件原封不动地添加到你的大jar包中,并操作类路径以获取jar-within-jar文件?
第一点很容易检查: 用 jar -tvf yourJar.jar 列出你的jar包内容,或使用存档查看器图形化地查看。请注意,.jar 基本上是一个 .zip,因此您可以重命名扩展名,然后使用能够查看 .zip 文件的工具。
关于第二部分,我有一个想法: 你能否构建一个简单的 Java 主类,打印出 System.getProperty("java.class.path")?即使Scala类不能运行,Java类也应该能够在该jar包中运行。

当IntelliJ构建Jar文件时,它只是将jar文件添加到Jar文件中。这是一个不错的技巧。我尝试了你的想法,它返回了jar文件。也就是说,它打印出了“myScalaApp.jar”。这是否意味着它没有读取清单来获取jar文件内部的内容? - Skuge
确切地说,问题就在这里:那些类不在你的ScalaApp.jar中,也就是说它们并不直接存在于其目录结构中。你的类路径需要包含对每个“内部”jar的引用,但我不确定语法是否正确或是否存在。我尝试过将所有组件jar文件都解压缩,并重新打包到一个jar文件中,效果很好,但是除非你有一个工具(或者ant任务)可以执行此操作,否则很费力。 - Carl Smotricz
是的,看起来清单文件没有被遵守。由于我只能提供较小的帮助,建议您尝试再次提问,而不涉及Scala。许多人可能可以在纯Java环境下回答这个问题。 - Carl Smotricz

2

至少有三种方法可以实现这一点(其中一种适用于Netbeans,但在Idea中也应该有效)

  • 使用jarjar,如此处所述
  • 使用此页面上的想法(不太优雅,但最简单) - 从scala-library.jar中解压缩Scala目录,并将此目录添加到您的jar文件中。
  • 使用此页面上的想法(适用于NB) - 将"scala-library.jar"添加到您的项目库中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接