I want to compile a kotlin file with a dependency / import
package_a.kt
// file: package_a.kt
package package_a
fun function_from_package_a(){
println(" hurray function_from_package_a was called ! ")
}
main.kt
// file: main.kt
import package_a.*
fun main() {
function_from_package_a();
println("main function was executed")
}
compiling is working with
$ kotlinc package_a.kt -d package_a.jar
$ kotlinc main.kt -classpath package_a.jar -d main.jar
but when i run the main.jar with java, i will get an error:
$ java -jar main.jar
Exception in thread "main" java.lang.NoClassDefFoundError: package_a/Package_aKt
at MainKt.main(main.kt:8)
at MainKt.main(main.kt)
Caused by: java.lang.ClassNotFoundException: package_a.Package_aKt
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:602)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:522)
... 2 more
does anybody know why?
CodePudding user response:
i found the solution for the problem
i changed my main.kt to
// file: main.kt
package test
import package_a.*
fun main() {
function_from_package_a();
println("main function was executed")
}
and then i can run it with
java -cp main.jar:package_a.jar test.MainKt
CodePudding user response:
When you compile the main class with the command:
kotlinc main.kt -classpath package_a.jar -d main.jar
the resulting main.jar only contains the main class object. It does not contain the objects in the package_a package. The -classpath option to kotlinc only allows symbols to be resolved during compilation. It doesn't cause anything else to be included in the resulting main.jar file.
Therefore, when you execute:
java -jar main.jar
Java does not know where to get the contents of the package_a package.
You might then think that this would work:
java -classpath package_a.jar -jar main.jar
but this does not work either, because when you specify that Java execute a jar file, all directives for finding dependent objects, be they in the jar file or elsewhere, have to come from the jar file itself. The -classpath option is ignored when the -jar option is used.
UPDATE: I saw the OPs posted answer only after posting my own. That alternate way of running the code works because the -jar option is not being used, and so the -classpath option is not ignored, and so the indicated command tells Java what to execute and also tells it where to find all of the necessary class files.
NOTE: No changes were necessary to the original source files. The main class does not need to be in a named package to be able to refer to it on the command line. This command would have executed the code in its original form:
java -cp main.jar:package_a.jar MainKt
Another option would be to include the dependent package in the main.jar file. I tried this, and it works fine. It's a bit involved, as you have to get the manifest right so that Java knows which class to execute. Because the OP has found another way, I won't elaborate here.
