此问题与this one有关 .
我得到了这个Gradle任务:
task fatJar(type: Jar) {
manifest {
attributes 'Implementation-Title': 'rpi-sense-hat-lib',
'Implementation-Version': version,
'Main-Class': 'io.github.lunarwatcher.pi.sensehat.Tests'
}
baseName = project.name
from {
configurations.compile.collect {
it.isDirectory() ? it : zipTree(it)
}
}
with jar
}
并且只有一个依赖项,将测试依赖项放在一边:
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
testImplementation group: 'junit', name: 'junit', version: '4.12'
}
从IDE运行正常 . 但是,当我部署到我的Raspberry Pi(或在本地使用jar gradlew fatJar
结果)时,我得到以下异常:
$ java -jar java-sense-hat-1.0a.jar
Exception in thread "main" java.lang.NoClassDefFoundError: kotlin/jvm/internal/Intrinsics
at io.github.lunarwatcher.pi.sensehat.UtilsKt.getSenseHat(Utils.kt:18)
at io.github.lunarwatcher.pi.sensehat.SenseHat.<init>(SenseHat.java:12)
at io.github.lunarwatcher.pi.sensehat.Tests.main(Tests.java:9)
Caused by: java.lang.ClassNotFoundException: kotlin.jvm.internal.Intrinsics
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(Unknown Source)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(Unknown Source)
at java.base/java.lang.ClassLoader.loadClass(Unknown Source)
... 3 more
这是由这一行引发的:
return Optional.empty()
在Kotlin方法中返回 Optional<File>
. Answer on related question:
kotlin-runtime必须在类路径中并使用$ echo $ CLASSPATH进行验证 . 或者你必须将kotlin-runtime添加到maven,然后使用mvn编译程序集在jar本身内组装:single,
这意味着kotlin-runtime不是stdlib的一部分:
Kotlin Runtime(不推荐使用,改为使用kotlin-stdlib工件)
我使用 kotlin-stdlib-jdk8
并且它在IDE中工作 . 仅出于测试目的,使用 kotlin-stdlib
而不是改变任何东西 .
另外,用 compile
替换 implementation
会修复它 .
在我在问题顶部链接的帖子中,有一个建议在fatJar任务中使用 runtime
. 所以:
task fatJar(type: Jar) {
manifest {
attributes 'Implementation-Title': 'rpi-sense-hat-lib',
'Implementation-Version': version,
'Main-Class': 'io.github.lunarwatcher.pi.sensehat.Tests'
}
baseName = project.name
from {
configurations.compile.collect {
it.isDirectory() ? it : zipTree(it)
}
configurations.runtime.collect {
it.isDirectory() ? it : zipTree(it)
}
}
with jar
}
仍然不包括依赖项,程序崩溃 .
那么为什么不将实现添加为配置来复制?
我试过了 . 我最终得到了这个:
task fatJar(type: Jar) {
manifest {
attributes 'Implementation-Title': 'rpi-sense-hat-lib',
'Implementation-Version': version,
'Main-Class': 'io.github.lunarwatcher.pi.sensehat.Tests'
}
baseName = project.name
from {
configurations.compile.collect {
it.isDirectory() ? it : zipTree(it)
}
configurations.runtime.collect {
it.isDirectory() ? it : zipTree(it)
}
configurations.implementation.collect {
it.isDirectory() ? it : zipTree(it)
}
}
with jar
}
还有一个例外:
不允许直接解析配置'实施'
所以,考虑到:
-
compile
而不是implementation
有效 -
运行时异常来自Kotlin不在类路径中
-
它适用于IDE
-
将
implementation
子句添加到fatJar
任务会使编译崩溃并产生单独的异常
使用 implementation
关键字时,如何在Gradle 4.4中生成包含所有依赖项的jar?
解决建议的副本:它只适用于compile关键字,而不是 implementation
. 此外, compile
已被弃用,支持 implementation
和 api
,这就是为什么在声明依赖项不是一个选项时使用 compile
而不是 implementation
.
1 回答
你有没有试过Shadow Plugin:
编辑:
您也可以这样做(如_114659_的答案中所述):
但是你必须重复所有的实现依赖关系作为fatJar依赖 . 对于你当前的项目来说没关系,因为你只有一个依赖项,但对于任何更大的项目,它都会变得一团糟......
编辑2:
正如@Zoe在评论中指出的那样,这也是一个可以接受的解决方案:
但是根据source code发出通知
runtimeClasspath
是runtimeOnly
,runtime
和implementation
的组合,根据具体情况可能会或可能不合适 - 例如,您可能不希望包含runtime
依赖项,因为它们是由容器提供的 .