Running an uber jar from sbt assembly results in error: Could not find or load main class

Running an uber jar from sbt assembly results in error: Could not find or load main class

我使用 sbt 程序集插件将 spark 作业打包为 uber-jar。 build.sbt 指定一个可运行的主程序作为生成的 uber-jar

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

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

java -jar assembly.jar

结果

Error: Could not find or load main class 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 核心 类 正在加载,但我没有看到任何打包的 类 正在加载。

这里可能有什么问题?

经过广泛的调查(阅读:拔头发),事实证明这种行为是恶意 INDEX.LIST 来自降落在 META-INF 目录中的扁平化 jar 文件之一的结果生成的 uber-jar。

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

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

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

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


更新:

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

的情况时,此答案适用