从sbt程序集运行超级jar会导致错误:无法找到或加载主类

时间:2017-09-18 20:34:43

标签: java jar classloader sbt-assembly

我使用sbt程序集插件将一个spark工作打包为超级jar。 build.sbt指定一个可运行的main作为生成的uber-jar的目标

mainClass in assembly := Some("com.foo.Bar")

正确创建程序集后,运行预期的命令:

java -jar assembly.jar

结果

  

错误:无法找到或加载主类com.foo.Bar

使用替代方法,如java -cp assembly.jar com.foo.Bar,会出现相同的错误消息。

然后,我在新目录中提取了uber-jar的内容。我可以看到我的com/foo/目录和Bar.class文件。 从我尝试的解压缩目录的根目录开始:

java -cp . com.foo.Bar

我得到了正确的结果。

进一步试图找出错误的原因,我试过:

java -verbose -jar assembly.jar

我可以看到正在加载java核心类,但是我没有看到我的任何打包类被加载。

这里可能出现什么问题?

1 个答案:

答案 0 :(得分:19)

经过广泛的调查(读取:拔出头发),事实证明这种行为是由于其中一个平展的jar文件落在INDEX.LIST目录中的流氓META-INF造成的。结果是超级罐子。

JAR file spec之后,INDEX.LIST(如果存在)指示要加载Jar文件中的哪些包。

为避免这种情况,我们使用规则更新了mergeStrategy,以避免对生成的META-INF目录造成任何污染:

case PathList("META-INF", xs @ _*) => MergeStrategy.discard

这解决了这个问题并恢复了我的理智。

更新

经过一些额外搜索,结果default merge strategy正确照顾INDEX.LIST。当自定义合并策略包含处理META-INF pathSpec

的案例时,此答案适用