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

maa*_*asg 11 java jar classloader sbt-assembly

我使用sbt程序集插件将一个spark工作打包为uber-jar.该build.sbt指定可运行的主要得到的尤伯杯罐的目标

mainClass in assembly := Some("com.foo.Bar")
Run Code Online (Sandbox Code Playgroud)

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

java -jar assembly.jar
Run Code Online (Sandbox Code Playgroud)

结果是

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

使用替代方法,就像java -cp assembly.jar com.foo.Bar给出相同的错误消息.

然后,我在新目录中提取了超级jar的内容.我可以看到我的com/foo/目录和Bar.class文件.从我提取的目录的根目录我尝试:

java -cp . com.foo.Bar
Run Code Online (Sandbox Code Playgroud)

我得到了正确的结果.

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

java -verbose -jar assembly.jar
Run Code Online (Sandbox Code Playgroud)

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

这可能有什么问题?

maa*_*asg 29

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

遵循JAR文件规范,INDEX.LIST如果存在,则指示要加载Jar文件中的哪些包.

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

case PathList("META-INF", xs @ _*) => MergeStrategy.discard
Run Code Online (Sandbox Code Playgroud)

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


更新:

经过一些额外的搜索后,事实证明默认的合并策略需要妥善处理INDEX.LIST.当自定义合并策略包含处理该案例的案例时,此答案适用META-INF pathSpec