Java 如何在内存中编译kotlin文件并检查结果?
到目前为止我有Java 如何在内存中编译kotlin文件并检查结果?,java,android,jvm,kotlin,kotlinc,Java,Android,Jvm,Kotlin,Kotlinc,到目前为止我有 import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler MyProjectCompiler.initialize("SampleKtFileOutput") .packageName("com.test.sample") .compile(File(someFile.path)) .result { ktSource: String -> K2JVMCompiler() .exec(Sy
import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
MyProjectCompiler.initialize("SampleKtFileOutput")
.packageName("com.test.sample")
.compile(File(someFile.path))
.result { ktSource: String -> K2JVMCompiler()
.exec(System.out, /** arguments here?*/) }
这将手动启动编译器,但我希望编译内存中第一个编译器(MyProjectCompiler
,它生成kotlin源代码)的结果字符串,并检查结果,而不写入文件
如果可能的话,我想包括当前类路径上的所有内容。阅读
K2JVMCompiler
类的源代码,编译器似乎只支持文件编译。深入挖掘,伪造org.jetbrains.kotlin.codegen.KotlinCodegenFacade
静态方法compileCorrectFiles
的条目似乎过于复杂
您最好使用文件系统来实现这一点。临时RAM磁盘可能适合您的需要。(这是内置的macOS)我发现最简单的方法是使用类似于原始问题中的代码,然后使用
java.io.tmpdir
。下面是一个可重用的解决方案:
将kotlin编译器添加为测试依赖项:
testCompile group: 'org.jetbrains.kotlin', name: 'kotlin-compiler', version: "$kotlin_version"
编译器的包装器:
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 {
it.asFile().exists() && it.asFile().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
}
将类作为接口实例加载
Initializer(compileOutputDir)
.createInstance<Consumer<String>>("com.test.Example")
?.accept("Hello, world!")
初始值设定项(compileOutputDir)
.createInstance(“com.test.Example”)
?接受(“你好,世界!”)
输出将如预期的那样:
found:'Hello,world!'代码>有没有办法使用JSR223 API来实现这一点?我对itJSR 223不太熟悉,它只允许您在应用程序中添加脚本功能,可以更轻松地调整应用程序,但它不会帮助您使用RAM驱动器或在RAM中编译。这就是REPL的运行方式,不是吗?可以用它来定义我一个接一个编译的每个类型,然后用这种方式进行测试吗?我已经浏览了kotlin的源代码,但我真的不知道如何通过编程方式运行REPL。imho:REPL是命令行实用程序。另一方面,JSR233允许您在应用程序中运行预先编写的脚本,而无需REPL。我已经用它在应用程序中运行了Beanshell和Jython脚本,例如,这有助于创建用户定义的行为。不管怎样,我认为找出REPL可能比手动编译和类加载容易得多。我至少会用字符串进行测试,但这并不难,因为我在IR中仍然有类。虽然在任何地方都找不到关于它的任何信息,因此可能需要一些工作。我尝试了代码,但缺少三件事:MockClasswriter
、codegeoutputfile
和compileOutputDir
assertTrue(JvmCompile.exe(codegenOutputFile, compileOutputDir))
Initializer(compileOutputDir)
.createInstance<Consumer<String>>("com.test.Example")
?.accept("Hello, world!")