此问题与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运行时都必须位于类路径中,并使用$ echo $ CLASSPATH进行验证。
或者您必须将kotlin-runtime添加到maven,然后使用mvn compile assembly:single
在jar本身中进行汇编
这意味着kotlin运行时未包含在类路径中。在继续回答“将kotlin运行时添加到依赖项”之前,它是stdlib的一部分:
Kotlin运行时(不建议使用,而是使用kotlin-stdlib工件)
我使用kotlin-stdlib-jdk8
,它可以在IDE中使用。仅出于测试目的,使用kotlin-stdlib
不会更改任何内容。
此外,将implementation
替换为compile
可以解决此问题。
在我在问题顶部链接的帖子中,建议在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
有用implementation
任务中添加fatJar
子句会使编译失败,并带有单独的异常使用implementation
关键字时,如何在Gradle 4.4中生成具有所有依赖项的jar?
解决建议的重复项:仅适用于compile关键字,不适用于implementation
。此外,不赞成使用compile
和implementation
来支持api
,这就是为什么在声明依赖性不是选项时使用compile
而不是implementation
的原因。
答案 0 :(得分:8)
您是否尝试过像Shadow Plugin那样:
shadowJar {
manifest {
attributes 'Implementation-Title': 'rpi-sense-hat-lib',
'Implementation-Version': version,
'Main-Class': 'io.github.lunarwatcher.pi.sensehat.Tests'
}
configurations = [project.configurations.compile, project.configurations.runtime]
}
编辑:
您也可以执行此操作(如对此question的答复中所述):
configurations {
fatJar
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
testImplementation group: 'junit', name: 'junit', version: '4.12'
fatJar "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
}
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.fatJar.collect {
it.isDirectory() ? it : zipTree(it)
}
}
with jar
}
,但是然后您必须将所有实现依赖项重复为fatJar依赖项。对于您当前的项目,这很好,因为您只有一个依赖项,但是对于任何更大的依赖项,都会变得一团糟...
编辑2:
正如@Zoe在评论中指出的那样,这也是可以接受的解决方案:
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.runtimeClasspath.collect {
it.isDirectory() ? it : zipTree(it)
}
}
with jar
}
但是请注意,根据source code,runtimeClasspath
是runtimeOnly
,runtime
和implementation
的组合,根据是否需要,可能取决于这种情况-例如,您可能不希望包含runtime
依赖项,因为它们是由容器提供的。