Lorcan
01/28/2025, 2:25 PMdata class UserSchema(
val foo: String,
val bar: Long,
)
class RuntimeKotlinCompiler {
private class ByteArrayClassLoader(private val classBytes: ByteArray) : ClassLoader() {
override fun findClass(name: String): Class<*> {
return defineClass(name, classBytes, 0, classBytes.size)
}
}
private val template = """
import kotlin.Boolean
class UserRule {
fun evaluate(transaction: ${UserSchema::class.qualifiedName}): Boolean {
return %s
}
}
""".trimIndent()
fun compileKotlinCode(userCode: String): ByteArray {
val fullCode = template.format(userCode)
val tempDir = createTempDirectory()
val sourceFile = File(tempDir, "UserRule.kt").apply {
writeText(fullCode)
}
val messageCollector = object : MessageCollector {
override fun clear() {}
override fun hasErrors(): Boolean = false
override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageSourceLocation?) {
if (severity == CompilerMessageSeverity.ERROR) {
throw RuntimeException("Compilation error: $message")
}
}
}
val compiler = K2JVMCompiler()
val arguments = K2JVMCompilerArguments().apply {
destination = tempDir.absolutePath
classpath = System.getProperty("java.class.path")
jvmTarget = "1.8"
noStdlib = true
noReflect = true
freeArgs = listOf(sourceFile.absolutePath)
}
val exitCode = compiler.exec(messageCollector, Services.EMPTY, arguments)
if (exitCode.code != 0) {
throw RuntimeException("Compilation failed with exit code: $exitCode")
}
val compiledFile = File(tempDir, "UserRule.class")
return compiledFile.readBytes().also {
tempDir.deleteRecursively()
}
}
private fun createTempDirectory(): File {
return File.createTempFile("kotlin-compiler", "").let { file ->
file.delete()
file.mkdir()
file
}
}
fun executeCompiledCode(compiledBytes: ByteArray, userSchema: UserSchema): Boolean {
val classLoader = ByteArrayClassLoader(compiledBytes)
val userRuleClass = classLoader.loadClass("UserRule")
val instance = userRuleClass.getDeclaredConstructor().newInstance()
val evaluateMethod = userRuleClass.getMethod("evaluate", UserSchema::class.java)
return evaluateMethod.invoke(instance, userSchema) as Boolean
}
}
The newb help link in the channel is 4 years old now. I'm wondering where the best resources are now for getting to grips with the compiler for this type of project so i can expand on it?