# Running Kotlin Scripts with bindings from a Kotlin program using ScriptEngine

**URL:** <https://discuss.kotlinlang.org/t/running-kotlin-scripts-with-bindings-from-a-kotlin-program-using-scriptengine/19726>\
**Category:** Support\
**Created:** [October 30, 2020, 12:28pm UTC](https://discuss.kotlinlang.org/t/running-kotlin-scripts-with-bindings-from-a-kotlin-program-using-scriptengine/19726 "2020-10-30T12:28:48Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![nomemory](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/nomemory/32/8100_2.png) [@nomemory](https://discuss.kotlinlang.org/u/nomemory)\
**Post date:** [October 30, 2020, 12:28pm UTC](https://discuss.kotlinlang.org/t/running-kotlin-scripts-with-bindings-from-a-kotlin-program-using-scriptengine/19726/1 "2020-10-30T12:28:48Z")

</div>

Hello,

I am currently implementing [a library](https://github.com/nomemory/mapneat) that is able to run Kotlin scripts (\*.kts) from a Kotlin program. The code kept in the .kts files is mostly configuration that I want to change it at runtime if needed.

The class responsible with running the scripts looks like this:

```
package net.andreinc.mapneat.scripting

import org.jetbrains.kotlin.cli.common.environment.setIdeaIoUseFallback
import java.io.File
import java.lang.IllegalStateException
import java.nio.charset.Charset
import javax.script.*

object KotlinScriptRunner {

init {
    setIdeaIoUseFallback()
}

private val scriptManager = ScriptEngineManager(currentClassLoader())
private val scriptEngine : ScriptEngine = scriptManager.getEngineByExtension("kts")!!

fun getScriptEngine() : ScriptEngine {
    return this.scriptEngine
}

private fun readResource(resource: String, charset: Charset = Charsets.UTF_8) : String {
    val resourceUrl = javaClass.classLoader?.getResource(resource)
    return resourceUrl!!.readText(charset)
}

private fun currentClassLoader() : ClassLoader {
    return Thread.currentThread().contextClassLoader
}

fun eval(scriptContent: String, compileFirst: Boolean = true, bindings: Map<String, String> = mapOf()) : Any {
    if (compileFirst) {
        when (scriptEngine) {
            is Compilable -> {
                val compiledCode = scriptEngine.compile(scriptContent)
                return compiledCode.eval(scriptEngine.createBindings().apply { putAll(bindings) })
            }
            else -> throw IllegalStateException("Kotlin is not an instance of Compilable. Cannot compile script.")
        }
    }
    else {
        return scriptEngine.eval(scriptContent, scriptEngine.createBindings().apply { putAll(bindings) })
    }
}

fun evalFile(file: String, readAsResource: Boolean, compileFirst: Boolean = true, bindings: Map<String, String> = mapOf()) : Any {
    val content : String = if (readAsResource) readResource(file) else File(file).readText()
    return eval(content, compileFirst, bindings)
}

```

}

As you can see the `eval` method allows me to send bindings as a map (variables that I can pass to the script).

Problem is in the Script those variables have to be accessed from `bindings[variableName]`. E.g .kts:

```
json(bindings["json"] as String) {
    "name" *= "$.name"
    "a" /= bindings["a"] as String
}.getPrettyString()

```

Problem is that in IntelliJ `bindings[]` is an unresolved reference and the Scripts gets invalidated. I can run the script from the command-line, but in IntelliJ i have problems, because this invalidates my project:

- Has anyone of you knows how to handle this situation in IntelliJ?
- Is there another way to pass bindings to the Kotlin Script?
- Given the experimental nature of the code I am using, is the code looking ok from your perspective?

---

<div class="post-metadata">

**Author:** ![bjonnh](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/bjonnh/32/8106_2.png) [@bjonnh](https://discuss.kotlinlang.org/u/bjonnh)\
**Post date:** [October 31, 2020, 3:55am UTC](https://discuss.kotlinlang.org/t/running-kotlin-scripts-with-bindings-from-a-kotlin-program-using-scriptengine/19726/2 "2020-10-31T03:55:45Z")

</div>

You can have a look at a simple implementation I played with today. I am giving context by using an implicit receiver: [konbu/main.kt at 26fa43c4819f773fa0d94fd8ea219eddb2316d4b · bjonnh/konbu · GitHub](https://github.com/bjonnh/konbu/blob/26fa43c4819f773fa0d94fd8ea219eddb2316d4b/src/main/kotlin/net/nprod/konbu/main.kt)

---

<div class="post-metadata">

**Author:** ![nomemory](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/nomemory/32/8100_2.png) [@nomemory](https://discuss.kotlinlang.org/u/nomemory)\
**Post date:** [November 4, 2020, 11:43am UTC](https://discuss.kotlinlang.org/t/running-kotlin-scripts-with-bindings-from-a-kotlin-program-using-scriptengine/19726/3 "2020-11-04T11:43:54Z")

</div>

@bjonnh I’ve tried to wrap my head around this solution. I kinda understand what you did there, but where did you found the documentation for this ? I’ve looked through the web and couldn’t find any documentation about implicit receivers.

Do you have any source for this ?

Also how “stable” is going to be this approach in the long run, looking at the code I see “experimental” in the package name, this means that the API might break in the future, correct ?

All in all, thanks for the help, I really appreciate it!

---

<div class="post-metadata">

**Author:** ![bjonnh](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/bjonnh/32/8106_2.png) [@bjonnh](https://discuss.kotlinlang.org/u/bjonnh)\
**Post date:** [November 4, 2020, 7:23pm UTC](https://discuss.kotlinlang.org/t/running-kotlin-scripts-with-bindings-from-a-kotlin-program-using-scriptengine/19726/4 "2020-11-04T19:23:17Z")

</div>

@nomemory there is really little doc so i looked at kotlinls scripting repository where they have examples and used github’s code search (super useful for poorly documented things). For the implicit receivers i found that by looking in intellij code completion and found it that way then looked into kotlin’s code to understand how it works…

As it is not documented i expect those things to break yeah…

As you can see it was quite an adventure…

---

<div class="post-metadata">

**Author:** ![nomemory](https://sea1.discourse-cdn.com/flex019/user_avatar/discuss.kotlinlang.org/nomemory/32/8100_2.png) [@nomemory](https://discuss.kotlinlang.org/u/nomemory)\
**Post date:** [November 4, 2020, 8:39pm UTC](https://discuss.kotlinlang.org/t/running-kotlin-scripts-with-bindings-from-a-kotlin-program-using-scriptengine/19726/5 "2020-11-04T20:39:32Z")

</div>

@bjonnh I did the same, and I believe I found a small bug [https://youtrack.jetbrains.com/issue/KT-43176](https://youtrack.jetbrains.com/issue/KT-43176) regarding the implementation.

I eventually end-up using your repo and the kotlin repos to understand how to use the API. Eventually I made it work. Quite an adventure.

Thanks for the suggestion.
