JSR-223 compliant scripting engine implementation for Kotlin, enabling Java applications to execute Kotlin scripts dynamically through the standard Java scripting API.
npx @tessl/cli install tessl/maven-org-jetbrains-kotlin--kotlin-scripting-jsr223@2.2.0Kotlin Scripting JSR-223 provides a JSR-223 (Scripting for the Java Platform) compliant implementation for Kotlin, enabling Java applications to execute Kotlin scripts dynamically at runtime through the standard Java scripting API. This library implements the JSR-223 ScriptEngine interface to allow seamless integration of Kotlin scripting capabilities into Java applications.
Gradle:
dependencies {
implementation("org.jetbrains.kotlin:kotlin-scripting-jsr223:2.2.0")
}Maven:
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-scripting-jsr223</artifactId>
<version>2.2.0</version>
</dependency>import kotlin.script.experimental.jsr223.KotlinJsr223DefaultScriptEngineFactory
import kotlin.script.experimental.jsr223.KotlinJsr223DefaultScript
import kotlin.script.experimental.jsr223.KOTLIN_JSR223_RESOLVE_FROM_CLASSLOADER_PROPERTYFor Java applications using JSR-223:
import javax.script.ScriptEngineManager;
import javax.script.ScriptEngine;
import javax.script.Bindings;import javax.script.*;
// Get Kotlin script engine through JSR-223
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByExtension("kts");
// Execute simple Kotlin script
Object result = engine.eval("val x = 5 + 3; x");
System.out.println(result); // Output: 8
// Using bindings to pass data between Java and Kotlin
Bindings bindings = engine.createBindings();
bindings.put("name", "World");
bindings.put("count", 42);
Object greeting = engine.eval("\"Hello, $name! Count: $count\"", bindings);
System.out.println(greeting); // Output: Hello, World! Count: 42import kotlin.script.experimental.jsr223.KotlinJsr223DefaultScriptEngineFactory
val factory = KotlinJsr223DefaultScriptEngineFactory()
val engine = factory.scriptEngine
// Execute Kotlin script
val result = engine.eval("listOf(1, 2, 3).map { it * 2 }")The library is built around several key components:
Main entry point for creating Kotlin script engines through JSR-223.
class KotlinJsr223DefaultScriptEngineFactory : KotlinJsr223JvmScriptEngineFactoryBase() {
override fun getScriptEngine(): ScriptEngine
}The factory automatically configures dependency resolution from the current context classloader and provides caching for performance optimization.
Base template class for JSR-223 Kotlin scripts with integrated bindings support.
abstract class KotlinJsr223DefaultScript(val jsr223Bindings: Bindings) : ScriptTemplateWithBindings(jsr223Bindings) {
fun eval(script: String, newBindings: Bindings): Any?
fun eval(script: String): Any?
fun createBindings(): Bindings
}Usage Examples:
// Inside a script context, access bindings
val userName = jsr223Bindings["userName"] as String
val result = "Hello, $userName!"
// Evaluate another script with custom bindings
val customBindings = createBindings()
customBindings["value"] = 100
val computation = eval("value * 2", customBindings)
// Evaluate with current bindings
val simpleResult = eval("42 + 8")Default configurations for script compilation and evaluation.
object KotlinJsr223DefaultScriptCompilationConfiguration : ScriptCompilationConfiguration
object KotlinJsr223DefaultScriptEvaluationConfiguration : ScriptEvaluationConfigurationThese objects provide:
System property for controlling how dependencies are resolved.
const val KOTLIN_JSR223_RESOLVE_FROM_CLASSLOADER_PROPERTY: String =
"kotlin.jsr223.experimental.resolve.dependencies.from.context.classloader"Usage:
// Enable experimental direct classloader resolution
System.setProperty(
"kotlin.jsr223.experimental.resolve.dependencies.from.context.classloader",
"true"
);
// Create engine with experimental dependency resolution
ScriptEngine engine = new ScriptEngineManager().getEngineByExtension("kts");When set to "true", dependencies are resolved directly from the context classloader using reflection. Otherwise, the classpath is extracted first and used for dependency resolution.
The library integrates with standard Java exception handling patterns:
try {
Object result = engine.eval("invalid kotlin syntax }");
} catch (ScriptException e) {
System.err.println("Script compilation/execution error: " + e.getMessage());
}ScriptEngine engine = new ScriptEngineManager().getEngineByExtension("kts");
// Create custom bindings
Bindings bindings = engine.createBindings();
bindings.put("dataList", Arrays.asList(1, 2, 3, 4, 5));
bindings.put("multiplier", 3);
// Execute script with access to Java objects
String script = """
val processedData = (dataList as List<Int>).map { it * multiplier }
processedData.joinToString(", ")
""";
Object result = engine.eval(script, bindings); // "3, 6, 9, 12, 15"Scripts can access the full Kotlin standard library and any dependencies available on the classpath:
// Assuming kotlin-coroutines is on the classpath
String coroutineScript = """
import kotlinx.coroutines.*
runBlocking {
val deferred = async { delay(100); "Async result" }
deferred.await()
}
""";
Object asyncResult = engine.eval(coroutineScript);The library automatically registers with JSR-223 through the service provider mechanism:
META-INF/services/javax.script.ScriptEngineFactorykotlin.script.experimental.jsr223.KotlinJsr223DefaultScriptEngineFactoryThis enables automatic discovery by ScriptEngineManager.getEngineByExtension("kts") and ScriptEngineManager.getEngineByName("kotlin").
// From javax.script package (JSR-223 standard)
interface ScriptEngine {
fun eval(script: String): Any?
fun eval(script: String, bindings: Bindings): Any?
fun createBindings(): Bindings
// ... other JSR-223 methods
}
interface Bindings : MutableMap<String, Any?> {
// Standard map operations for variable binding
}
interface ScriptEngineFactory {
fun getScriptEngine(): ScriptEngine
// ... other factory methods
}
// From Kotlin scripting API
abstract class ScriptTemplateWithBindings(val bindings: Bindings)
class ScriptCompilationConfiguration
class ScriptEvaluationConfiguration