This question is related to this one -- however, due to the deprecation of compile
in favor of implementation
, it doesn't work. It does pick up dependencies that are declared with compile
. However, with it being deprecated, using it isn't an option (and we'd be right back here when it's removed anyway)
I got this Gradle task:
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
}
And there's just one dependency, looking aside test dependencies:
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
testImplementation group: 'junit', name: 'junit', version: '4.12'
}
Running from the IDE works fine. However, when I deploy to my Raspberry Pi (or use the jar gradlew fatJar
results in locally), I get this exception:
$ 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
Which is triggered by this line:
return Optional.empty()
in a Kotlin method returning an Optional<File>
. Answer on related question:
Either kotlin-runtime has to be in classpath and verify with $ echo $CLASSPATH.
Or you have to add kotlin-runtime to maven and then assemble inside the jar itself with mvn compile assembly:single,
Which means the kotlin-runtime isn't included in the classpath. Before you go ahead and answer "add kotlin-runtime to your dependencies", it's a part of the stdlib:
Kotlin Runtime (deprecated, use kotlin-stdlib artifact instead)
I use kotlin-stdlib-jdk8
and it works in the IDE. Just for testing purposes, using kotlin-stdlib
instead does not change anything.
In addition, replacing implementation
with compile
fixes it.
In the post I linked at the top of the question, there's a suggestion to use runtime
in the fatJar task. So:
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
}
The dependency is still not included, and the program crashes.
So why not add implementation as a configuration to copy from?
I tried. I ended up with this:
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
}
And an exception:
Resolving configuration 'implementation' directly is not allowed
So, considering:
compile
instead ofimplementation
works- The runtime exception is from Kotlin not being in the classpath
- It works in the IDE
- Adding an
implementation
clause to thefatJar
task crashes the compiling with a separate exception
How do I generate a jar with all dependencies in Gradle 4.4 when using the implementation
keyword?