Kotlin Scripting JVM host for executing and compiling Kotlin scripts in JVM environments with JSR-223 integration and comprehensive caching mechanisms
—
Complete JSR-223 (Java Scripting API) compatible implementation for seamless integration with existing Java scripting frameworks and applications.
Interface extending JSR-223 Invocable for function and method invocation with backward compatibility support.
/**
* JSR-223 invocable script engine interface with Kotlin-specific extensions
*/
interface KotlinJsr223InvocableScriptEngine : Invocable {
/** Optional wrapper for function/method invocation */
val invokeWrapper: InvokeWrapper?
/** Sequence of previously evaluated script instances for backward compatibility */
val backwardInstancesHistory: Sequence<Any>
/** Base class loader for script execution context */
val baseClassLoader: ClassLoader
/**
* Invokes a top-level function from previously evaluated scripts
* @param name Function name to invoke
* @param args Function arguments
* @returns Function result or null
*/
override fun invokeFunction(name: String?, vararg args: Any?): Any?
/**
* Invokes a method on a specific object instance
* @param thiz Object instance to invoke method on
* @param name Method name to invoke
* @param args Method arguments
* @returns Method result or null
*/
override fun invokeMethod(thiz: Any?, name: String?, vararg args: Any?): Any?
/**
* Gets an interface implementation from script context
* @param clasz Interface class to implement
* @returns Interface implementation or null
*/
override fun <T : Any> getInterface(clasz: Class<T>?): T?
/**
* Gets an interface implementation from specific object instance
* @param thiz Object instance to use as interface implementation
* @param clasz Interface class to implement
* @returns Interface implementation or null
*/
override fun <T : Any> getInterface(thiz: Any?, clasz: Class<T>?): T?
}Complete JSR-223 script engine implementation with REPL capabilities and context integration.
/**
* JSR-223 script engine implementation with REPL support
* @param factory Script engine factory instance
* @param baseCompilationConfiguration Base compilation configuration
* @param baseEvaluationConfiguration Base evaluation configuration
* @param getScriptArgs Function to extract script arguments from JSR-223 context
*/
class KotlinJsr223ScriptEngineImpl(
factory: ScriptEngineFactory,
baseCompilationConfiguration: ScriptCompilationConfiguration,
baseEvaluationConfiguration: ScriptEvaluationConfiguration,
val getScriptArgs: (context: ScriptContext) -> ScriptArgsWithTypes?
) : KotlinJsr223JvmScriptEngineBase(factory), KotlinJsr223InvocableScriptEngine {
/** JSR-223 host configuration with context integration */
val jsr223HostConfiguration: ScriptingHostConfiguration
/** Final compilation configuration with JSR-223 refinements */
val compilationConfiguration: ScriptCompilationConfiguration
/** Final evaluation configuration with JSR-223 refinements */
val evaluationConfiguration: ScriptEvaluationConfiguration
/** REPL compiler for incremental compilation */
val replCompiler: ReplCompilerWithoutCheck
/** REPL evaluator for script execution */
val replEvaluator: ReplFullEvaluator
/** Current REPL state */
val state: IReplStageState<*>
/**
* Creates new REPL state with thread synchronization
* @param lock Read-write lock for thread safety
* @returns New REPL stage state
*/
fun createState(lock: ReentrantReadWriteLock): IReplStageState<*>
/**
* Overrides script arguments from JSR-223 context
* @param context JSR-223 script context
* @returns Script arguments with types or null
*/
fun overrideScriptArgs(context: ScriptContext): ScriptArgsWithTypes?
/**
* Compiles and evaluates script code with context integration
* @param script Script code to execute
* @param context JSR-223 script context
* @returns Evaluation result
*/
fun compileAndEval(script: String, context: ScriptContext): Any?
}Usage Examples:
import kotlin.script.experimental.jvmhost.jsr223.*
import javax.script.*
// Create JSR-223 script manager
val manager = ScriptEngineManager()
// Register Kotlin script engine (typically done by service loader)
val factory = KotlinJsr223DefaultScriptEngineFactory()
manager.registerEngineExtension("kts", factory)
// Get Kotlin script engine
val engine = manager.getEngineByExtension("kts") as KotlinJsr223InvocableScriptEngine
// Basic script execution
val result = engine.eval("""
fun greet(name: String) = "Hello, ${'$'}name!"
val message = greet("World")
println(message)
message
""")
println("Script result: $result")
// Function invocation
val greeting = engine.invokeFunction("greet", "JSR-223")
println("Function result: $greeting")
// Context integration
val context = engine.context
context.setAttribute("userName", "Alice", ScriptContext.ENGINE_SCOPE)
context.setAttribute("userAge", 30, ScriptContext.ENGINE_SCOPE)
val contextResult = engine.eval("""
val user = mapOf("name" to userName, "age" to userAge)
println("User: ${'$'}user")
user
""")
// Interface implementation
interface Calculator {
fun add(a: Int, b: Int): Int
fun multiply(a: Int, b: Int): Int
}
engine.eval("""
fun add(a: Int, b: Int) = a + b
fun multiply(a: Int, b: Int) = a * b
""")
val calculator = engine.getInterface(Calculator::class.java)
println("5 + 3 = ${calculator.add(5, 3)}")
println("5 * 3 = ${calculator.multiply(5, 3)}")JSR-223 specific configuration keys and builders for customizing script engine behavior.
/** JSR-223 host configuration keys */
interface Jsr223HostConfigurationKeys
/** Builder for JSR-223 host configuration */
open class Jsr223HostConfigurationBuilder
/** JSR-223 compilation configuration keys */
interface Jsr223CompilationConfigurationKeys
/** Builder for JSR-223 compilation configuration */
open class Jsr223CompilationConfigurationBuilder
/** JSR-223 evaluation configuration keys */
interface Jsr223EvaluationConfigurationKeys
/** Builder for JSR-223 evaluation configuration */
open class Jsr223EvaluationConfigurationBuilderExtension properties for integrating JSR-223 configuration with standard Kotlin scripting configuration.
/** JSR-223 host configuration extension */
val ScriptingHostConfigurationKeys.jsr223: Jsr223HostConfigurationBuilder
/** JSR-223 compilation configuration extension */
val ScriptCompilationConfigurationKeys.jsr223: Jsr223CompilationConfigurationBuilder
/** JSR-223 evaluation configuration extension */
val ScriptEvaluationConfigurationKeys.jsr223: Jsr223EvaluationConfigurationBuilder/** Function to get JSR-223 script context from host configuration */
val Jsr223HostConfigurationKeys.getScriptContext: () -> ScriptContext?
/** Function to get JSR-223 script context from compilation configuration */
val Jsr223CompilationConfigurationKeys.getScriptContext: () -> ScriptContext?
/** Whether to import all JSR-223 context bindings as script properties */
val Jsr223CompilationConfigurationKeys.importAllBindings: Boolean
/** Function to get JSR-223 script context from evaluation configuration */
val Jsr223EvaluationConfigurationKeys.getScriptContext: () -> ScriptContext?Configuration Examples:
import kotlin.script.experimental.jvmhost.jsr223.*
import javax.script.ScriptContext
// Host configuration with JSR-223 integration
val hostConfig = ScriptingHostConfiguration {
jsr223 {
getScriptContext = {
// Provide access to current script context
getCurrentScriptContext()
}
}
}
// Compilation configuration with automatic binding import
val compilationConfig = ScriptCompilationConfiguration {
jsr223 {
getScriptContext = { getCurrentScriptContext() }
importAllBindings = true // Import all context bindings as script properties
}
// Standard Kotlin scripting configuration
dependencies(JvmDependency(kotlinStdlib))
}
// Evaluation configuration with context access
val evaluationConfig = ScriptEvaluationConfiguration {
jsr223 {
getScriptContext = { getCurrentScriptContext() }
}
// Provide additional context variables
providedProperties(
"scriptContext" to ScriptContext::class
)
}
// Create engine with custom configuration
val customEngine = KotlinJsr223ScriptEngineImpl(
factory = KotlinJsr223DefaultScriptEngineFactory(),
baseCompilationConfiguration = compilationConfig,
baseEvaluationConfiguration = evaluationConfig
) { context ->
// Extract script arguments from context
val args = context.getBindings(ScriptContext.ENGINE_SCOPE)["args"] as? Array<String>
args?.let { ScriptArgsWithTypes(it, arrayOf(Array<String>::class)) }
}Functions for integrating JSR-223 context properties with Kotlin script compilation and evaluation.
/**
* Configures provided properties from JSR-223 context for compilation
* @param context Script configuration refinement context
* @returns Updated compilation configuration or failure
*/
fun configureProvidedPropertiesFromJsr223Context(
context: ScriptConfigurationRefinementContext
): ResultWithDiagnostics<ScriptCompilationConfiguration>
/**
* Configures provided properties from JSR-223 context for evaluation
* @param context Script evaluation configuration refinement context
* @returns Updated evaluation configuration or failure
*/
fun configureProvidedPropertiesFromJsr223Context(
context: ScriptEvaluationConfigurationRefinementContext
): ResultWithDiagnostics<ScriptEvaluationConfiguration>Context Integration Example:
import kotlin.script.experimental.jvmhost.jsr223.*
import javax.script.*
// Setup context with properties
val context = SimpleScriptContext()
val bindings = context.getBindings(ScriptContext.ENGINE_SCOPE)
bindings["database"] = DatabaseConnection("localhost:5432")
bindings["logger"] = LoggerFactory.getLogger("script")
bindings["config"] = mapOf("debug" to true, "maxRetries" to 3)
// Custom engine with automatic context property configuration
val contextEngine = KotlinJsr223ScriptEngineImpl(
factory = KotlinJsr223DefaultScriptEngineFactory(),
baseCompilationConfiguration = ScriptCompilationConfiguration {
refineConfiguration {
onAnnotations { context ->
// Automatically configure properties from JSR-223 context
configureProvidedPropertiesFromJsr223Context(context)
}
}
},
baseEvaluationConfiguration = ScriptEvaluationConfiguration {
refineConfiguration {
beforeEvaluation { context ->
// Configure evaluation properties from JSR-223 context
configureProvidedPropertiesFromJsr223Context(context)
}
}
}
) { scriptContext ->
// No special argument processing needed
null
}
contextEngine.context = context
// Script can now access context properties directly
val result = contextEngine.eval("""
// Properties from JSR-223 context are automatically available
logger.info("Starting script execution")
val users = database.query("SELECT * FROM users")
logger.info("Found ${'$'}{users.size} users")
if (config["debug"] as Boolean) {
println("Debug mode enabled")
println("Max retries: ${'$'}{config["maxRetries"]}")
}
users.size
""")
println("Script found ${result} users")JSR-223 integration provides comprehensive error handling that bridges Kotlin diagnostics with JSR-223 exceptions.
// JSR-223 exceptions are automatically translated from Kotlin diagnostics
try {
val result = engine.eval("invalid kotlin syntax !!!")
} catch (e: ScriptException) {
println("Script compilation error: ${e.message}")
println("Line number: ${e.lineNumber}")
println("Column number: ${e.columnNumber}")
// Access original Kotlin diagnostics if available
val kotlinDiagnostics = e.cause as? ScriptDiagnosticException
kotlinDiagnostics?.diagnostics?.forEach { diagnostic ->
println("Kotlin diagnostic: ${diagnostic.severity} - ${diagnostic.message}")
}
}
// Function invocation errors
try {
val result = engine.invokeFunction("nonExistentFunction", "arg")
} catch (e: NoSuchMethodException) {
println("Function not found: ${e.message}")
}
// Interface implementation errors
try {
val impl = engine.getInterface(Calculator::class.java)
if (impl == null) {
println("Cannot create interface implementation - required functions not defined")
}
} catch (e: ClassCastException) {
println("Interface implementation error: ${e.message}")
}JSR-223 implementation provides thread-safe execution through proper synchronization and isolated state management.
import java.util.concurrent.*
val engine = manager.getEngineByExtension("kts") as KotlinJsr223InvocableScriptEngine
// Thread-safe concurrent execution
val executor = ForkJoinPool.commonPool()
val futures = (1..10).map { i ->
executor.submit(Callable {
val localContext = SimpleScriptContext()
localContext.setBindings(engine.createBindings(), ScriptContext.ENGINE_SCOPE)
localContext.setAttribute("threadId", i, ScriptContext.ENGINE_SCOPE)
engine.eval("""
println("Executing on thread ${'$'}threadId")
Thread.currentThread().name + " - " + threadId
""", localContext)
})
}
val results = futures.map { it.get() }
results.forEach { println("Result: $it") }// Reuse compiled scripts for better performance
val precompiledEngine = KotlinJsr223ScriptEngineImpl(
// Configuration optimized for repeated execution
baseCompilationConfiguration = ScriptCompilationConfiguration {
// Enable compilation caching
hostConfiguration(ScriptingHostConfiguration {
jvm {
compilationCache(FileBasedScriptCache(File("jsr223-cache")))
}
})
}
)
// Execute the same script multiple times efficiently
val scriptCode = """
fun factorial(n: Int): Long = if (n <= 1) 1 else n * factorial(n - 1)
factorial(args[0].toInt())
"""
val results = (1..10).map { n ->
val context = SimpleScriptContext()
context.setAttribute("args", arrayOf(n.toString()), ScriptContext.ENGINE_SCOPE)
precompiledEngine.eval(scriptCode, context)
}
println("Factorials: $results")Install with Tessl CLI
npx tessl i tessl/maven-org-jetbrains-kotlin--kotlin-scripting-jvm-host