【发布时间】:2018-06-26 21:02:41
【问题描述】:
这个问题与this one 有关——但是,由于compile 被implementation 弃用,它不起作用。它确实拾取使用compile 声明的依赖项。然而,随着它被弃用,使用它不是一种选择(无论如何,当它被删除时我们会马上回到这里)
我得到了这个 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()
在返回 Optional<File> 的 Kotlin 方法中。 Answer on related question:
kotlin-runtime 必须在类路径中并使用 $ echo $CLASSPATH 进行验证。
或者您必须将 kotlin-runtime 添加到 maven,然后使用 mvn compile assembly:single 在 jar 内部组装,
这意味着 kotlin-runtime 不包含在类路径中。在您继续回答“将 kotlin-runtime 添加到您的依赖项”之前,它是 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有效 - 运行时异常来自 Kotlin 不在类路径中
- 它在 IDE 中工作
- 向
fatJar任务添加implementation子句会导致编译崩溃并出现单独的异常
使用implementation 关键字时,如何在 Gradle 4.4 中生成包含所有依赖项的 jar?
【问题讨论】:
-
@ShafinMahmud 阅读了这个问题。它不适用于 implementation 关键字
-
如果你改写你的问题标题来更具体地描述问题会很好
-
@ShafinMahmud 您是否因为标题而标记为重复?帖子的内容涵盖了整个问题,包括为什么链接的问题不起作用
-
但是您的问题标题应该与现有的标题区分开来。无意冒犯,应该有一个清晰的标题来总结您的问题,如果已经有相关内容,则不是通用的。这将导致人们为您提供更多帮助