Trying to use Kotlin via javax.script (JSR 223) in a webapp

Hi, I’m trying to use Kotlin (v1.2.60) packaged in a .war file deployed to WildFly (v13.0.0.Final), to be accessed through the javax.script API (JSR 223). WEB-INF/lib contains the jars from mvn packages “org.jetbrains.kotlin:kotlin-compiler-embeddable:1.2.60” and “org.jetbrains.kotlin:kotlin-script-util:1.2.60”.

Trying a simple eval like this:

ScriptEngine e = new KotlinJsr223JvmLocalScriptEngineFactory().getScriptEngine();
e.eval("1+1");

Gives this stacktrace:

java.lang.IllegalStateException: Resource not found: /kotlin/jvm/JvmStatic.class
	at deployment.kotlin_script_test.war//org.jetbrains.kotlin.script.util.impl.PathUtilKt.getResourcePathForClass(pathUtil.kt:76)
	at deployment.kotlin_script_test.war//org.jetbrains.kotlin.script.util.KotlinJars.getLib(context.kt:147)
	at deployment.kotlin_script_test.war//org.jetbrains.kotlin.script.util.KotlinJars$stdlibOrNull$2.invoke(context.kt:151)
	at deployment.kotlin_script_test.war//org.jetbrains.kotlin.script.util.KotlinJars$stdlibOrNull$2.invoke(context.kt:119)
	at deployment.kotlin_script_test.war//kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
	at deployment.kotlin_script_test.war//org.jetbrains.kotlin.script.util.KotlinJars.getStdlibOrNull(context.kt)
	at deployment.kotlin_script_test.war//org.jetbrains.kotlin.script.util.KotlinJars.getKotlinScriptStandardJars(context.kt:168)
	at deployment.kotlin_script_test.war//org.jetbrains.kotlin.script.util.ContextKt.scriptCompilationClasspathFromContextOrStlib(context.kt:109)
	at deployment.kotlin_script_test.war//org.jetbrains.kotlin.script.util.ContextKt.scriptCompilationClasspathFromContextOrStlib$default(context.kt:106)
	at deployment.kotlin_script_test.war//org.jetbrains.kotlin.script.jsr223.KotlinJsr223JvmDaemonLocalEvalScriptEngineFactory.getScriptEngine(KotlinJsr223ScriptEngineFactoryExamples.kt:46)
	at deployment.kotlin_script_test.war//kotlin.KotlinEvaluator.eval(KotlinEvaluator.java:10)

Running the code in a standalone app outside a web container with the same dependencies works fine.

Any ideas? What am I missing? Is the Kotlin script engine ready to be run inside a webapp?

Thanks, John

1 Like

I’ve tried to debug this and found that the method extractRoot from libraries/tools/kotlin-script-util/src/main/kotlin/org/jetbrains/kotlin/script/util/impl/pathUtil.kt is called with an URL like this:

"vfs:/PATH_TO_EXPLODED_WAR/WEB-INF/lib/kotlin-stdlib-1.2.60.jar/kotlin/jvm/JvmStatic.class"

where “vfs” seems to be a special WildFly Virtual File System protocol which the extractRoot method cannot handle because it’s hard-wired to “jar” and “file”.

Any recommendations?

Seems this is an untested path. We’ll do something about it, but meanwhile, you can workaround it by specifying script compilation classpath explicitly via kotlin.compiler.classpath property. You’ll need to put at least kotlin-script-util there, and for any useful script, quite likely kotlin-stdlib as well.

1 Like

Thanks! I’ve added the jars to kotlin.compiler.classpath one after the other, getting various exceptions on the way. But with this classpath:

-Dkotlin.compiler.classpath=kotlin-stdlib.jar:kotlin-script-util.jar:kotlin-stdlib-common.jar:kotlin-script-runtime.jar:kotlin-compiler-embeddable.jar

I’m stuck with this:

ERROR [stderr] cannot extract: /org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment$Companion.class from vfs:/content/kotlin_script_test.war/WEB-INF/lib/kotlin-compiler-embeddable-1.2.60.jar/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment$Companion.class
ERROR [io.undertow.request] UT005023: Exception handling request to /kotlin_script_test/: java.lang.IllegalStateException: Resource not found: /org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment$Companion.class

I would be grateful if you could take this up in some future release.

Hi, I am getting exactly the same errors in v1.3.10 trying to do the same in OSGi runtime (equinox). Script Engine can be created with the compiler classpath workaround, but the errors come when I try to execute a script.

The kotlin script support is implemented by compiling the code at runtime and then executing the resulting code. It means you need access to the Kotlin compiler at runtime. It also means that this is not the fastest thing in the world.

@ilya.chernikov Is there maybe any news here on this topic? Still very much interested in using Kotlin as a script engine inside a web container.

IMO, this is exactly what the javax.script mechanism is for. There are situations where you cannot (or prefer not to) package everything at compile-time but deploy certain parts of your code or configuration-as-code at runtime. Using Kotlin, you’d of course have a small performance penalty when that code is run for the first time, but after that it will run and interoperate the same as pre-compiled code.

Unfortunately no news so far. I’ve created an issue for easier tracking - https://youtrack.jetbrains.com/issue/KT-30367. We’ll have a look, what could be done about it.

The original issue is that kotlin is not yet able to compile with classes directly from current classloader (as many interpreted languages like groovy and clojure can), so it needs to get a classpath in a form that the compiler will be able to use. And in a webapp environment this is not trivial.
There is an issue about this - https://youtrack.jetbrains.com/issue/KT-27956 - we’re going to address it in some not too distant future. And then these problems should go away.

2 Likes

Other readers please note: I needed to use the kotlin.script.classpath, rather than kotlin.compiler.classpath, to get this to work.