Kotlin JSR-223 ScriptEngineFactory within the fat jar - Cannot find kotlin compiler jar
Asked Answered
O

1

5

I have a fat jar where I'm trying to get the instance of Kotlin's ScriptEngine.

For the debugging purposes I'm iterating through available Script Engine Factories and getting the engines.

val scriptEngineManager = ScriptEngineManager()
for (factory in scriptEngineManager.engineFactories) {
    val scriptEngine = factory.scriptEngine
}

When it hits the Kotlin's engine, it fails with following exception:

Exception in thread "main" java.io.FileNotFoundException: Cannot find kotlin compiler jar, set kotlin.compiler.jar property to proper location
        at org.jetbrains.kotlin.script.jsr223.KotlinJsr223ScriptEngineFactoryExamplesKt$kotlinCompilerJar$2.invoke(KotlinJsr223ScriptEngineFactoryExamples.kt:100)
        at org.jetbrains.kotlin.script.jsr223.KotlinJsr223ScriptEngineFactoryExamplesKt$kotlinCompilerJar$2.invoke(KotlinJsr223ScriptEngineFactoryExamples.kt)
        at kotlin.SynchronizedLazyImpl.getValue(Lazy.kt:130)
        at org.jetbrains.kotlin.script.jsr223.KotlinJsr223ScriptEngineFactoryExamplesKt.getKotlinCompilerJar(KotlinJsr223ScriptEngineFactoryExamples.kt)
        at org.jetbrains.kotlin.script.jsr223.KotlinJsr223ScriptEngineFactoryExamplesKt.access$getKotlinCompilerJar$p(KotlinJsr223ScriptEngineFactoryExamples.kt:1)
        at org.jetbrains.kotlin.script.jsr223.KotlinJsr223JvmDaemonLocalEvalScriptEngineFactory.getScriptEngine(KotlinJsr223ScriptEngineFactoryExamples.kt:56)
        at davidsiro.invoices.InvoiceGeneratorKt.generateInvoice(invoiceGenerator.kt:16)
        at davidsiro.invoices.MainKt.main(main.kt:11)

My fat jar contains all of the dependencies (though unpacked), including Kotlin Compiler. I'm using Maven Assembly Plugin to build it, which configured like these:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-assembly-plugin</artifactId>
    <version>2.6</version>
    <executions>
        <execution>
            <id>make-assembly</id>
            <phase>package</phase>
            <goals>
                <goal>single</goal>
            </goals>
            <configuration>
                <archive>
                    <manifest>
                        <mainClass>${main.class}</mainClass>
                    </manifest>
                </archive>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>
        </execution>
    </executions>
</plugin>

Any ideas?

Update

For the record, I tried to both KotlinJsr223JvmLocalScriptEngineFactory and KotlinJsr223JvmDaemonLocalEvalScriptEngineFactory with the same result.

Olga answered 27/6, 2017 at 13:24 Comment(3)
make sure the resouces of META-INF is included or there is no duplicated files in that folder.Libertinage
I believe that's ok, it's something with way how the Kotlin's ScriptEngineFactory resolves the compiler class...Olga
well, may be kotlin module info was orverwrote.Libertinage
S
9

The JSR223 factories in the kotlin-script-util are trying to find the compiler jar in order to setup the compilation. In your case, you'll need to write your own factory to supply the script compilation classpath explicitly, e.g.

class MyScriptEngineFactory : KotlinJsr223JvmScriptEngineFactoryBase() {   
    override fun getScriptEngine(): ScriptEngine =
        KotlinJsr223JvmLocalScriptEngine(
            Disposer.newDisposable(),
            this,
            classpath, // !!! supply the script classpath here
            KotlinStandardJsr223ScriptTemplate::class.qualifiedName!!,
            { ctx, types -> ScriptArgsWithTypes(arrayOf(ctx.getBindings(ScriptContext.ENGINE_SCOPE)), types ?: emptyArray()) },
            arrayOf(Bindings::class)
        )
}

You need to put the following jars into classpath:

  • kotlin-script-util.jar - it contains the template class used as a superclass for the script
  • kotlin-script-runtime.jar - for base classes used in scripting
  • any other jars you'll need to use in your scripts, quite likely - kotlin-stdlib.jar

You may put your fat jar there instead, but that would mean that everything from it will be accessible from your scripts. Not talking about the overheads for the compiler.

Sabulous answered 28/6, 2017 at 8:3 Comment(3)
Thanks, that seems to be the way to go. Anyway, could you please elaborate on Not talking about the overheads for the compiler ?Olga
@DavidSiro on the resolving stage the compiler will seek types in the compilation classpath, so the larger the search scope the bigger the overheads.Sabulous
I can't seem to resolve KotlinJsr223JvmLocalScriptEngine during compile timeThrombus

© 2022 - 2024 — McMap. All rights reserved.