Kotlin JVM scripting support library that provides core functionality for executing and evaluating Kotlin scripts on the JVM platform
—
JVM implementations of compiled scripts with serialization support, module management, and ClassLoader creation capabilities. The compiled script system provides efficient script storage, caching, and execution with proper metadata handling.
Core JVM implementation of compiled scripts with serialization support and metadata management.
/**
* JVM implementation of compiled script with serialization support
* Provides metadata about compiled script and manages execution context
*/
open class KJvmCompiledScript : CompiledScript, Serializable {
/** Source location identifier for debugging and error reporting */
override val sourceLocationId: String?
/** Configuration used during compilation */
override val compilationConfiguration: ScriptCompilationConfiguration
/** List of other scripts this script depends on */
override val otherScripts: List<CompiledScript>
/** Fully qualified name of the compiled script class */
val scriptClassFQName: String
/** Result field information if script produces a result */
override val resultField: Pair<String, KotlinType>?
/**
* Get the compiled script class for execution
* @param scriptEvaluationConfiguration Configuration for class loading
* @return Result containing the script class or diagnostics
*/
override suspend fun getClass(
scriptEvaluationConfiguration: ScriptEvaluationConfiguration?
): ResultWithDiagnostics<KClass<*>>
/**
* Get the compiled module containing this script
* @return KJvmCompiledModule or null if not available
*/
fun getCompiledModule(): KJvmCompiledModule?
}Usage Examples:
import kotlin.script.experimental.jvm.impl.KJvmCompiledScript
import kotlin.script.experimental.api.*
// Access compiled script properties
val compiledScript: KJvmCompiledScript = // ... obtained from compilation
println("Script class: ${compiledScript.scriptClassFQName}")
println("Source location: ${compiledScript.sourceLocationId}")
println("Dependencies: ${compiledScript.otherScripts.size}")
// Get script class for execution
val evaluationConfig = ScriptEvaluationConfiguration {
// ... configuration
}
val classResult = compiledScript.getClass(evaluationConfig)
when (classResult) {
is ResultWithDiagnostics.Success -> {
val scriptClass = classResult.value
println("Successfully loaded class: ${scriptClass.qualifiedName}")
}
is ResultWithDiagnostics.Failure -> {
println("Failed to load class:")
classResult.reports.forEach { println(" ${it.message}") }
}
}Base interface for compiled JVM modules with ClassLoader management capabilities.
/**
* Represents a compiled JVM module
* Provides ClassLoader creation for script execution
*/
interface KJvmCompiledModule {
/**
* Create ClassLoader for this module
* @param baseClassLoader Parent ClassLoader (null for system ClassLoader)
* @return ClassLoader containing module classes and resources
*/
fun createClassLoader(baseClassLoader: ClassLoader?): ClassLoader
}Compiled module stored entirely in memory with bytecode management.
/**
* In-memory compiled module with bytecode storage
* Suitable for dynamic compilation and caching scenarios
*/
interface KJvmCompiledModuleInMemory : KJvmCompiledModule {
/** Map of class names to their compiled bytecode */
val compilerOutputFiles: Map<String, ByteArray>
}Usage Example:
// Create in-memory module
val inMemoryModule = object : KJvmCompiledModuleInMemory {
override val compilerOutputFiles = mapOf(
"MyScript.class" to compiledBytecode,
"MyScript\$Helper.class" to helperClassBytecode
)
override fun createClassLoader(baseClassLoader: ClassLoader?): ClassLoader {
return InMemoryClassLoader(compilerOutputFiles, baseClassLoader)
}
}
// Use module ClassLoader
val moduleClassLoader = inMemoryModule.createClassLoader(
Thread.currentThread().contextClassLoader
)Compiled module loaded from filesystem classpath entries.
/**
* Module loaded from classpath files
* @param classpath Collection of JAR files and directories containing compiled classes
*/
class KJvmCompiledModuleFromClassPath(
val classpath: Collection<File>
) : KJvmCompiledModule {
/**
* Create ClassLoader from classpath files
* @param baseClassLoader Parent ClassLoader
* @return URLClassLoader containing classpath entries
*/
override fun createClassLoader(baseClassLoader: ClassLoader?): ClassLoader
}Usage Examples:
import java.io.File
// Create module from JAR files
val jarFiles = listOf(
File("/path/to/compiled-script.jar"),
File("/path/to/dependencies.jar")
)
val classpathModule = KJvmCompiledModuleFromClassPath(jarFiles)
// Create ClassLoader for execution
val classLoader = classpathModule.createClassLoader(
ClassLoader.getSystemClassLoader()
)
// Load and execute script class
val scriptClass = classLoader.loadClass("com.example.MyCompiledScript")
val scriptInstance = scriptClass.getDeclaredConstructor().newInstance()Compiled module that wraps an existing ClassLoader.
/**
* Module from existing ClassLoader
* @param moduleClassLoader Existing ClassLoader containing module classes
*/
class KJvmCompiledModuleFromClassLoader(
val moduleClassLoader: ClassLoader
) : KJvmCompiledModule {
/**
* Create ClassLoader using existing module ClassLoader as parent
* @param baseClassLoader Additional parent ClassLoader (optional)
* @return ClassLoader chain with proper delegation
*/
override fun createClassLoader(baseClassLoader: ClassLoader?): ClassLoader
}Usage Example:
// Use existing plugin ClassLoader as module
val pluginClassLoader = MyPlugin::class.java.classLoader
val module = KJvmCompiledModuleFromClassLoader(pluginClassLoader)
// Create execution ClassLoader
val executionClassLoader = module.createClassLoader(
Thread.currentThread().contextClassLoader
)Advanced ClassLoader implementation that combines multiple ClassLoader sources.
/**
* ClassLoader that combines fallback and parent loaders
* Provides sophisticated class loading delegation
* @param fallbackLoader Primary ClassLoader for class resolution
* @param parentLoader Secondary ClassLoader for delegation
*/
class DualClassLoader(
fallbackLoader: ClassLoader,
parentLoader: ClassLoader?
) : ClassLoader {
/** Find class in fallback loader */
override fun findClass(name: String): Class<*>
/** Get resource stream with fallback logic */
override fun getResourceAsStream(name: String): InputStream?
/** Find resources across both loaders */
override fun findResources(name: String): Enumeration<URL>
/** Find single resource with fallback */
override fun findResource(name: String): URL?
/**
* Wrapper ClassLoader for delegation
*/
class Wrapper(parent: ClassLoader) : ClassLoader(parent)
}Usage Example:
// Create dual ClassLoader for complex scenarios
val applicationClassLoader = MyApp::class.java.classLoader
val pluginClassLoader = loadPluginClassLoader()
val dualClassLoader = DualClassLoader(
fallbackLoader = pluginClassLoader,
parentLoader = applicationClassLoader
)
// Use for script execution with access to both contexts
val module = KJvmCompiledModuleFromClassLoader(dualClassLoader)Extension functions for compiled script management and serialization.
/**
* Get or create actual ClassLoader for script evaluation
* @param evaluationConfiguration Configuration for ClassLoader creation
* @return ClassLoader suitable for script execution
*/
fun KJvmCompiledScript.getOrCreateActualClassloader(
evaluationConfiguration: ScriptEvaluationConfiguration
): ClassLoader
/**
* Create copy of script without module information
* @return New KJvmCompiledScript instance without module reference
*/
fun KJvmCompiledScript.copyWithoutModule(): KJvmCompiledScript
/**
* Serialize compiled script to byte array
* @return Serialized script data
*/
fun KJvmCompiledScript.toBytes(): ByteArray
/**
* Create script from ClassLoader and class name
* @param scriptClassFQName Fully qualified script class name
* @param classLoader ClassLoader containing the script class
* @return KJvmCompiledScript instance
*/
fun createScriptFromClassLoader(
scriptClassFQName: String,
classLoader: ClassLoader
): KJvmCompiledScriptUsage Examples:
// Get execution ClassLoader
val executionClassLoader = compiledScript.getOrCreateActualClassloader(evaluationConfig)
// Create lightweight copy for caching
val cacheableScript = compiledScript.copyWithoutModule()
// Serialize for persistent storage
val serializedData = compiledScript.toBytes()
val restoredScript = deserializeScript(serializedData)
// Create script from existing compiled class
val scriptFromClassLoader = createScriptFromClassLoader(
"com.example.MyScript",
MyApp::class.java.classLoader
)Constants and utilities for script metadata handling.
/** Path for script metadata in JAR files */
const val KOTLIN_SCRIPT_METADATA_PATH = "META-INF/kotlin/script"
/** File extension for Kotlin script metadata files */
const val KOTLIN_SCRIPT_METADATA_EXTENSION_WITH_DOT = ".kotlin_script"
/**
* Generate metadata path for script class
* @param scriptClassFQName Fully qualified script class name
* @return Metadata file path within JAR/directory structure
*/
fun scriptMetadataPath(scriptClassFQName: String): StringUsage Example:
// Generate metadata path for script
val scriptClassName = "com.example.MyScript"
val metadataPath = scriptMetadataPath(scriptClassName)
// Returns: "META-INF/kotlin/script/com/example/MyScript.kotlin_script"
// Use in JAR file creation
val jarEntry = JarEntry(metadataPath)
jarOutputStream.putNextEntry(jarEntry)
jarOutputStream.write(scriptMetadata)class ScriptCacheManager {
private val compiledScripts = mutableMapOf<String, KJvmCompiledScript>()
fun cacheScript(sourceId: String, script: KJvmCompiledScript) {
// Cache lightweight version without module
compiledScripts[sourceId] = script.copyWithoutModule()
}
fun getScript(sourceId: String, evaluationConfig: ScriptEvaluationConfiguration): KJvmCompiledScript? {
return compiledScripts[sourceId]?.let { cached ->
// Recreate with proper ClassLoader
val classLoader = cached.getOrCreateActualClassloader(evaluationConfig)
createScriptFromClassLoader(cached.scriptClassFQName, classLoader)
}
}
}class HotDeploymentManager {
private var currentModule: KJvmCompiledModule? = null
fun deployNewVersion(compiledClassPath: Collection<File>) {
currentModule = KJvmCompiledModuleFromClassPath(compiledClassPath)
}
fun createExecutionClassLoader(): ClassLoader? {
return currentModule?.createClassLoader(
Thread.currentThread().contextClassLoader
)
}
}Install with Tessl CLI
npx tessl i tessl/maven-org-jetbrains-kotlin--kotlin-scripting-jvm