Kotlin-compiler-embeddable: exception on Kotlin script evaluation

I got stuck with the exception which occurs on Kotlin script evaluation:

java.lang.IllegalStateException: Unable to find extension point configuration extensions/compiler.xml
    	at org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment$Companion.registerApplicationExtensionPointsAndExtensionsFrom(KotlinCoreEnvironment.kt:524)
    	at org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment$Companion.createApplicationEnvironment(KotlinCoreEnvironment.kt:481)
    	at org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment$Companion.getOrCreateApplicationEnvironmentForProduction(KotlinCoreEnvironment.kt:450)
    	at org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment$Companion.createForProduction(KotlinCoreEnvironment.kt:395)
    	at org.jetbrains.kotlin.cli.jvm.repl.GenericReplChecker.<init>(GenericReplChecker.kt:63)
    	at org.jetbrains.kotlin.cli.jvm.repl.GenericReplCompiler.<init>(GenericReplCompiler.kt:53)
    	at org.jetbrains.kotlin.cli.jvm.repl.GenericReplCompiler.<init>(GenericReplCompiler.kt:51)
    	at org.jetbrains.kotlin.script.jsr223.KotlinJsr223JvmLocalScriptEngine$replCompiler$2.invoke(KotlinJsr223JvmLocalScriptEngine.kt:45)
    	at org.jetbrains.kotlin.script.jsr223.KotlinJsr223JvmLocalScriptEngine$replCompiler$2.invoke(KotlinJsr223JvmLocalScriptEngine.kt:36)
    	at kotlin.SynchronizedLazyImpl.getValue(Lazy.kt:131)
    	at org.jetbrains.kotlin.script.jsr223.KotlinJsr223JvmLocalScriptEngine.getReplCompiler(KotlinJsr223JvmLocalScriptEngine.kt)
    	at org.jetbrains.kotlin.script.jsr223.KotlinJsr223JvmLocalScriptEngine$localEvaluator$2.invoke(KotlinJsr223JvmLocalScriptEngine.kt:51)
    	at org.jetbrains.kotlin.script.jsr223.KotlinJsr223JvmLocalScriptEngine$localEvaluator$2.invoke(KotlinJsr223JvmLocalScriptEngine.kt:36)
    	at kotlin.SynchronizedLazyImpl.getValue(Lazy.kt:131)
    	at org.jetbrains.kotlin.script.jsr223.KotlinJsr223JvmLocalScriptEngine.getLocalEvaluator(KotlinJsr223JvmLocalScriptEngine.kt)
    	at org.jetbrains.kotlin.script.jsr223.KotlinJsr223JvmLocalScriptEngine.getReplEvaluator(KotlinJsr223JvmLocalScriptEngine.kt:53)
    	at org.jetbrains.kotlin.script.jsr223.KotlinJsr223JvmLocalScriptEngine.createState(KotlinJsr223JvmLocalScriptEngine.kt:57)
    	at org.jetbrains.kotlin.cli.common.repl.KotlinJsr223JvmScriptEngineBase.createState$default(KotlinJsr223JvmScriptEngineBase.kt:46)
    	at org.jetbrains.kotlin.cli.common.repl.KotlinJsr223JvmScriptEngineBase.getCurrentState(KotlinJsr223JvmScriptEngineBase.kt:53)
    	at org.jetbrains.kotlin.cli.common.repl.KotlinJsr223JvmScriptEngineBase.nextCodeLine(KotlinJsr223JvmScriptEngineBase.kt:44)
    	at org.jetbrains.kotlin.cli.common.repl.KotlinJsr223JvmScriptEngineBase.compileAndEval(KotlinJsr223JvmScriptEngineBase.kt:59)
    	at org.jetbrains.kotlin.cli.common.repl.KotlinJsr223JvmScriptEngineBase.eval(KotlinJsr223JvmScriptEngineBase.kt:31)
    	at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:264)
...

Got it on production env and unable to reproduce it locally in IntelliJ.

The script evaluation code is:

        setIdeaIoUseFallback()
        val script: String = /* some Kotlin script */
        val engine = ScriptEngineManager().getEngineByExtension("kts")!!
        engine.eval(script)

Java Runtime 8.

Dependencies are:

  • org.jetbrains.kotlin:kotlin-script-runtime:1.2.20
  • org.jetbrains.kotlin:kotlin-script-util:1.2.20
  • org.jetbrains.kotlin:kotlin-compiler-embeddable:1.2.20

Does anyone know what causes it or what to do?

1 Like

Exactly the same on Kotlin 1.2.21

The exception means that it cannot find mentioned xml file in resources and other possible locations. This file should be a part of the kotlin-compiler.jar. And it is expected to be a part of the application’s classpath.
In an environment with some inttellij idea jars loaded, there could be interferences that prevent the compiler from detecting it parts properly. In this case, I’d recommend using KotlinJsr223JvmDaemonLocalEvalScriptEngineFactory which will execute the script compilation out of process (in a daemon). Or try to properly isolate the scripting part with an appropriate classloader.

1 Like

For those who interested the problem was with Spring Boot fat jar.

mvn spring-boot:run works fine but java -jar raises the exception above.

Solution: unpack Kotlin compiler libraries (see Spring Boot reference).

Also if you reference some classes in scripts you should also unpack corresponding jars as well + write your own implementation of the script engine factory inherited from KotlinJsr223JvmScriptEngineFactoryBase.

2 Likes

Hey Ilya,

Could you please share any details about implementation own ScriptEngineFactory?

I solved the issue by unpacking all jars that can be mentioned from scripts, but a script can import internal project classes and I got stuck with it. Internal project classes are not in the classpath and I’m getting unresolved reference exception.

This implementation works for Kotlin 1.2.51 and Spring Boot 1.5.13:

/**
 * Special Kotlin-script engine factory that adds script's dependencies to the script evaluator classpath.
 */
class SpringBootKotlinScriptEngineFactory  : KotlinJsr223JvmScriptEngineFactoryBase() {
    override fun getScriptEngine(): ScriptEngine {
        val extractedJarLocation = <some of the classes referenced by the script>::class.java.protectionDomain.codeSource.location.toURI()
        val jarDirectory = try {
            Paths.get(extractedJarLocation).parent
        } catch (e: FileSystemNotFoundException) {
            logger.error(e) { "Script engine creation error: can't get JAR directory for $extractedJarLocation" }
            throw e
        }

        val classpath = Files.list(jarDirectory)
                .filter { it.fileName.endsWith(".jar") }
                .map { it.toFile() }
                .collect(Collectors.toCollection { mutableListOf<File>() })

        classpath += scriptCompilationClasspathFromContext("kotlin-script-util.jar", wholeClasspath = true)

        return KotlinJsr223JvmLocalScriptEngine(
                this,
                classpath,
                KotlinStandardJsr223ScriptTemplate::class.qualifiedName!!,
                { ctx, types ->
                    ScriptArgsWithTypes(arrayOf(ctx.getBindings(ScriptContext.ENGINE_SCOPE)), types ?: emptyArray())
                },
                arrayOf(Bindings::class)
        )
    }

    companion object {
        private val logger = KotlinLogging.logger {  }
    }
}

Usage:
SpringBootKotlinScriptEngineFactory().scriptEngine.also { it.eval(script) }

2 Likes

Thank you very much, Ilya!

Very helpful!

Had the same issue when using Spring Boot, solved it by using the Shadow gradle plugin instead of BootJar as described here: Example build.gradle.kt to build a shadow jar for java and kotlin application | Fat Jar In Kotlin DSL

org.springframework.boot spring-boot-maven-plugin true -Dfile.encoding=UTF-8 org.jetbrains.kotlin kotlin-compiler-embeddable

thank you ,this works

Seems I have a very similar version with kotlin-compiler-embeddable-1.6.10.jar and spring-boot-2
Unpacking the dependency doesn’t help.
As well as the suggested solution
ScriptEngineManager(<class>::class.java.classLoader).getEngineByExtension("kts") just returns null

Spring Boot 3.2.0, just using compiler-embeddable 1.9.20 to get AST… still failing with this message if ran with java -jar boot.jar.

thanks for the tips!

after some research here’s the way i decided to go:

tasks.named<BootJar>("bootJar") {
  requiresUnpack("**/kotlin-*.jar")
}

this seems to be the simplest and most generic to me.

i use gradle, there should be similar function for maven plugin, i believe.