Yuutsuna
Yuutsuna

Reputation: 352

Running a Kotlin script in Kotlin code resulting in ClassCastException due to class loader differences

I want to load a kotlin script inside my program. I want to get the result of the script (the object returned) and use it in my kotlin code.

Here's what I have for my main method:

fun loadScript(scriptPath: String): SomeClass? {
    val scriptFile = File(scriptPath)
    val cl = SomeClass::class.java.classLoader

    val evalConfig = ScriptCompilationConfiguration {
        jvm {
            this.dependenciesFromClassloader(classLoader = cl, wholeClasspath = true)
        }
        ide {
            acceptedLocations(ScriptAcceptedLocation.Everywhere)
        }
        defaultImports("model.*")
    }

    val evalResult = BasicJvmScriptingHost().eval(
        scriptFile.toScriptSource(),
        evalConfig,
        ScriptEvaluationConfiguration {
            jvm {
                baseClassLoader(cl)
            }
        }
    )

    return when (val result = evalResult) {
        is ResultWithDiagnostics.Success -> {
            println(SomeClass::class.java.classLoader)
            println(result.value.returnValue.scriptInstance!!::class.java.classLoader)
            result.value.returnValue.scriptInstance as SomeClass
        }
        is ResultWithDiagnostics.Failure -> {
            println("Script execution failed: ${result.reports}")
            null
        }
    }
}

fun main() {

    val scriptResult = loadScript("script.kts") //?: return

    println(scriptResult)

    scriptResult!!.hello()

}

Here's the SomeClass code:

package model

class SomeClass {

    fun hello() {
        println("Hello World")
    }

}

fun getSomeObject() = SomeClass()

Here's the script code:

getSomeObject()

My issue is that i keep getting the following error:

Exception in thread "main" java.lang.ClassCastException: class Script cannot be cast to class model.SomeClass (Script is in unnamed module of loader org.jetbrains.kotlin.scripting.compiler.plugin.impl.CompiledScriptClassLoader @526fc044; model.SomeClass is in unnamed module of loader 'app')
    at MainKt.loadScript(Main.kt:272)
    at MainKt.main(Main.kt:283)
    at MainKt.main(Main.kt)

When I try to print the class loader I see i have:

jdk.internal.loader.ClassLoaders$AppClassLoader@76ed5528 for SomeClass::class.java.classLoader

and

org.jetbrains.kotlin.scripting.compiler.plugin.impl.CompiledScriptClassLoader@526fc044 for result.value.returnValue.scriptInstance!!::class.java.classLoader

Of course I understand the issue is with the class loader and that despite having the same name, the SomeClass object instanciated in the script is different than the SomeClass I try to cast into. What I don't understand is why this is happening when I specify the same class loader in the ScriptCompilationConfiguration and ScriptEvaluationConfiguration

Upvotes: 1

Views: 38

Answers (0)

Related Questions