执行JAR之后,Scala SBT Shell中的java.lang.NoSuchMethodError

问题描述

在打包并执行带有SBT(1.3.13版)的Scala应用程序(版本为2.12.0的build.sbt,但实际上已安装2.13.3)之后,出现以下错误

Exception in thread "main" java.lang.NoSuchMethodError: scala.Predef$.wrapRefArray([Ljava/lang/Object;)Lscala/collection/mutable/WrappedArray;
    at org.example.GreetWorld$.printMessage(GreetWorld.scala:5)

引起错误的源文件GreetWorld.scala如下所示:

package org.example

object GreetWorld {
      def printMessage(theMessage:String):Unit = {
            println(s"${theMessage} from me")
      }
}

正在调用上面文件的主文件如下:

package org.example

object HelloWorld {
    def main(args: Array[String]) = {
        GreetWorld.printMessage("Hello")
    }
}

有人知道根本原因吗?起初,我认为这与选择Java 11的SBT Shell有关,但是即使将Windows的JAVA_HOME更改为Java 8,我仍然会遇到相同的错误。在SBT Shell中编译并运行它可以正常工作。只有JAR执行失败。

解决方法

错误非常简单。运行package时,您将创建一个 JAR ,其中仅包含与您的源代码相对应的类,仅此而已。而且您的代码取决于Scala stdlib,因此,如果尝试使用java - jar运行它,它将失败,并出现类路径错误。

您有4种解决方案:

  1. 直接使用scala运行 JAR 。但是,您需要使用与编译时相同的主要版本。

  2. 在运行时将 Scala 库jar放入类路径中。这基本上与上面相同。同样,您必须使用相同的主要版本。

  3. 使用sbt-assembly创建一个其中已经包含Scala stdlib (以及任何其他依赖项)的uber jar。

  4. 使用sbt-native-packager创建一个本机可分发内容,它将为您设置所有内容。

对于本地开发和测试,选择1通常是最好的选择。
对于简单的项目,恕我直言,选项3是最简单的选择。
对于非常复杂的项目,选项4非常受欢迎。