I have mixed Java
& Kotlin
code in a demo project which I want to run from command line
. For only java, I am able to run the program with java -jar foo.jar
but when I use any class from Kotlin
code, it generates java.lang.NoClassDefFoundError: kotlin/jvm/internal/Intrinsics
I have tried different solutions and checked the jar
file. It contains both the classes but I guess kotlin-runtime
is missing from jar.
Here is build.gradle file
plugins {
id 'java-library'
id 'org.jetbrains.kotlin.jvm'
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin/'
test.java.srcDirs += 'src/test/kotlin/'
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
testImplementation 'junit:junit:4.12'
}
jar {
manifest {
attributes 'Main-Class': 'com.mallaudin.App'
}
from {
configurations.compile.collect {
it.isDirectory()? it: zipTree(it)
}
}
}
Content of generated jar
file
.
├── com
│ └── mallaudin
│ ├── App.class
│ └── User.class
└── META-INF
├── basics.kotlin_module
└── MANIFEST.MF
Content of MANIFEST.MF
Manifest-Version: 1.0
Main-Class: com.mallaudin.App
Exception I get when I run jar
form command line
allaudin@geek ~/Desktop/KotlinLab (master) $ java -jar basics/build/libs/basics.jar
Exception in thread "main" java.lang.NoClassDefFoundError: kotlin/jvm/internal/Intrinsics
at com.mallaudin.User.<init>(User.kt)
at com.mallaudin.App.main(App.java:5)
Caused by: java.lang.ClassNotFoundException: kotlin.jvm.internal.Intrinsics
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:583)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:190)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:499)
... 2 more
Even if it's interop you can't mix Java and Kotlin in the same file. If you really want to have static methods/variables you can use an companion object . You can also access create a "real" static method in your JVM by using @JvmStatic . By using @JvmStatic you can use Java to access your Static methods like before.
Kotlin is designed with Java interoperability in mind. Existing Java code can be called from Kotlin in a natural way, and Kotlin code can be used from Java rather smoothly as well.
Kotlin has been designed from the beginning to fully interoperate with Java, and both JetBrains and Google have pushed in that direction. For instance, IntelliJ and Android Studio allow users to convert files from Java to Kotlin.
The issue is in the way you build your fat jar. While you use the more recent and recommended implementation
scope for your dependencies, you are only adding to the fat jar the content of the compile
configuration.
You should replace the configuration to be used in the fat jar by runtimeClasspath
which is the full set of runtime components.
That is:
jar {
manifest {
attributes 'Main-Class': 'com.mallaudin.App'
}
from {
configurations.runtimeClasspath.collect {
it.isDirectory()? it: zipTree(it)
}
}
}
Have a look at the documentation to understand the different dependency configurations for a java project.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With