I've just started using Kotlin and I'm having some issues understanding how JAR files work. I have two files:
hello.kt
class HelloWorld {
public fun speak() {
println("hello world")
}
}
main.kt
fun main() {
val hello = HelloWorld()
hello.speak()
}
My project structure is:
root
|-hello.kt
|-main.kt
My intention is build the Kotlin application spreading its classes amongst dirrent JAR files. I've used
kotlinc hello.kt -d hello.jar
kotlinc main.kt -cp hello.jar -include-runtime -d main.jar
to build the JAR files. These two commands execute without any error. I'm having trouble understanding how to execute the application.
So far I've tried
java -cp hello.jar -jar main.jar
to run the application but I get this error:
Exception in thread "main" java.lang.NoClassDefFoundError: HelloWorld
at MainKt.main(main.kt:2)
at MainKt.main(main.kt)
Caused by: java.lang.ClassNotFoundException: HelloWorld
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:526)
... 2 more
I've also tried to follow the answer to this question which shows the same issue, but running
java -cp main.jar:hello.jar MainKt
gives me the following error
Error: Could not find or load main class MainKt
Caused by: java.lang.ClassNotFoundException: MainKt
I'm new to Kotlin and JVM in general but I cannot find a solution.
As a first note, you would usually use a build tool such as Gradle to do the compilation and packaging for you. However, for learning purposes, it's always nice to know how things fit together under the hood.
In your case, you're compiling things correctly. However, there are issues with how you run your application using the java
command. First, you cannot mix -cp
and -jar
, as per the documentation:
When you use -jar, the specified JAR file is the source of all user classes, and other class path settings are ignored. If you're using JAR files, then see jar.
In short, you have to choose between using -jar
with an executable jar file containing all the classpath information, or using -cp
with all the jars you need + the main class name.
Since you're not fiddling with jar manifests, you're not creating an executable jar, so you should stick to the -cp
option. You need to provide all the jars needed in the -cp
option (separated with :
on linux or mac, and with ;
on Windows), and the main class name at the end of the command:
java -cp "hello.jar;main.jar" MainKt
The name of the main class MainKt
is derived from the name of the file containing your main()
function and the package name inside the file, as defined (albeit subtly) in the Kotlin documentation.
You can also check this answer for more details.