2

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?

Jonas Frey
  • 65
  • 6

2 Answers2

1

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.

CryptoFool
  • 21,719
  • 5
  • 26
  • 44
  • It would be nice/helpful to see the "dependent package" solution with the manifest that you mention here. – demerphq Jul 04 '23 at 16:21
0

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
Jonas Frey
  • 65
  • 6
  • I'm glad you found an acceptable answer. Maybe you'll still find my answer valuable to better understand just what is going on here. – CryptoFool Jan 16 '22 at 02:54