Search code examples
kotlinpluginsjarruntimeclassloader

loading a jar file at runtime java.lang.NoClassDefFoundError: kotlin/jvm/internal/markers/KMappedMarker


I have foo.jar that contains Foo:

class Foo: Bar { ... }

bar.jar that contains Bar:

abstract class Bar { ... }

Then I have baz.jar that loads Foo dynamically:

val jarFile = JarFile("./foo.jar")
val e: Enumeration<JarEntry> = jarFile.entries()

val urls = arrayOf(URL("jar:file:foo.jar!/"))
val cl = URLClassLoader.newInstance(urls)

Thread.currentThread().contextClassLoader = cl // With or without same result.

val list = mutableListOf<Class<*>>()
while (e.hasMoreElements()) {
val je: JarEntry = e.nextElement()
...
cl.loadClass(className)

And run it as follow:

java -cp ./bar.jar -jar ./baz.jar 

First, I'm confused that I get a "ClassNotFoundException" even though bar.jar is in the classpath. I get around this problem by loading dynamically ./bar.jar before ./foo.jar as in the code above.

Then now I get NoClassDefFoundError: kotlin/jvm/internal/markers/KMappedMarker

The kotlin runtime is already packed in the foo.jar.

jar -xvf foo/build/libs/foo-1.0.jar | grep std
extracted: BOOT-INF/lib/kotlin-stdlib-1.4.10.jar

I've also created a fat-jar for bar.jar so it contains kotlin-stdlib and kotlin-reflect but I'm still getting the same error.

Can anyone explain me what's going on?


Solution

  • For anyone interested I finally make it working by changing:

    val cl = URLClassLoader.newInstance(urls)
    

    to this:

    val cl = URLClassLoader.newInstance(urls, this::class.java.classLoader)
    

    No need for fat-jar nor additional -cp options.