Exposing JVM (Kotlin) classes defined with a JSR223 ScriptEngine

Viewed 93

I'm trying to access a class defined in a script, evaluated with ScriptEngine.

Consider the following snippet:

package com.example

interface Foo
{
    fun bar()
}

val script = """
import com.example.Foo

class MyFoo : Foo
{
    override fun bar() = println("Hello from MyFoo::bar")
}
"""

fun main()
{
    val scriptEngineManager = ScriptEngineManager()
    val scriptEngine = scriptEngineManager.getEngineByName("kotlin")
    scriptEngine.eval(script)
}

This runs successfully, and now I'd like to instantiate MyFoo in the host code.

The only way I've managed to do so successfully is by using ScriptEngine::eval to return a reference to the class, by evaluating an expression referencing it:

fun main()
{
    val scriptEngineManager = ScriptEngineManager()
    val scriptEngine = scriptEngineManager.getEngineByName("kotlin")
    scriptEngine.eval(script)
    
    // -- See below --
    val fooKClass = scriptEngine.eval("MyFoo::class") as KClass<Foo>
    val foo = fooKClass.createInstance()
    foo.bar()
}

This too, runs successfullly, writing Hello from MyFoo::bar to standard out.

However, is there no way to add the script-defined class MyFoo to the host JVM classdefs?

fun main()
{
    val scriptEngineManager = ScriptEngineManager()
    val scriptEngine = scriptEngineManager.getEngineByName("kotlin")
    scriptEngine.eval(script)
    
    // -- See below --
    val fooKClass = Class.forName("MyFoo").kotlin as KClass<Foo>
    val foo = fooKClass.createInstance()
    foo.bar()
}

The above predictably fails with a java.lang.ClassNotFoundException: MyFoo.

Is dynamically evaluating and returning (from the ScriptEngine) the Class<*> or KClass<*> instance the only way to access it from the host JVM?

0 Answers
Related