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
的情况时,此答案适用
我使用 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