Skip to content

Instantly share code, notes, and snippets.

@oshai
Created October 23, 2018 11:42
Show Gist options
  • Save oshai/9dc447166dc792b8c95fa804dc696551 to your computer and use it in GitHub Desktop.
Save oshai/9dc447166dc792b8c95fa804dc696551 to your computer and use it in GitHub Desktop.
load a class from source code string
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector
import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
import org.jetbrains.kotlin.config.Services
import java.io.File
import java.io.FileNotFoundException
import java.io.IOException
import java.io.PrintWriter
import java.net.URLClassLoader
import java.nio.file.Files
import java.util.concurrent.ThreadLocalRandom
import kotlin.reflect.full.createInstance
/*
pom changes:
<kotlin.version>1.3.0-rc-190</kotlin.version>
<repository>
<id>kotlin-eap</id>
<url>http://dl.bintray.com/kotlin/kotlin-eap/</url>
</repository>
<repository>
<id>kotlin-dev</id>
<url>http://dl.bintray.com/kotlin/kotlin-dev/</url>
</repository>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-script-util</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-compiler-embeddable</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-script-runtime</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-scripting-jvm-host</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-compiler</artifactId>
<version>${kotlin.version}</version>
</dependency>
*/
inline fun <reified T> createAndLoad(className: String, classString: String): T {
val random = ThreadLocalRandom.current()
val dir: File = Files.createTempDirectory(System.currentTimeMillis().toString()+ "_" + random.nextInt()).toFile()
try {
val codegenOutputFile = File(dir.absolutePath + "/source.kt")
val writer = PrintWriter(codegenOutputFile, "UTF-8")
writer.println(classString)
writer.close()
val compileOutputDir = dir
println(JvmCompile.exe(codegenOutputFile, compileOutputDir)) //should be true
return Initializer(compileOutputDir)
.createInstance<T>(className)!!
// ?.accept("Hello, world!")
} finally {
delete(dir)
}
}
@Throws(IOException::class)
fun delete(f: File) {
if (f.isDirectory()) {
for (c in f.listFiles())
delete(c)
}
if (!f.delete())
throw FileNotFoundException("Failed to delete file: $f")
}
object JvmCompile {
fun exe(input: File, output: File): Boolean = K2JVMCompiler().run {
val args = K2JVMCompilerArguments().apply {
freeArgs = listOf(input.absolutePath)
loadBuiltInsFromDependencies = true
destination = output.absolutePath
classpath =
System.getProperty("java.class.path")
.split(System.getProperty("path.separator"))
.filter {
File(it).exists() && File(it).canRead()
}.joinToString(":")
noStdlib = true
noReflect = true
skipRuntimeVersionCheck = true
reportPerf = true
}
output.deleteOnExit()
execImpl(
PrintingMessageCollector(
System.out,
MessageRenderer.WITHOUT_PATHS, true),
Services.EMPTY,
args)
}.code == 0
}
class Initializer(private val root: File) {
val loader = URLClassLoader(
listOf(root.toURI().toURL()).toTypedArray(),
this::class.java.classLoader)
@Suppress("UNCHECKED_CAST")
inline fun <reified T> loadCompiledObject(clazzName: String): T? = loader.loadClass(clazzName).kotlin.objectInstance as T
@Suppress("UNCHECKED_CAST")
inline fun <reified T> createInstance(clazzName: String): T? = loader.loadClass(clazzName).kotlin.createInstance() as T
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment