java - 如何在内存中运行编译 kotlin 文件的测试并检查结果?

标签 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(System.out, /** arguments here?*/) }

这会手动启动编译器,但我想在内存中从第一个编译器(生成 kotlin 源的 MyProjectCompiler)编译生成的字符串,并在不写入文件的情况下检查结果。

如果可能,我想在当前类路径中包含所有内容。

最佳答案

我发现最简单的方法是使用类似于原始问题中的代码的内容并使用 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

}

示例测试用例:

先制作一个kotlin源文件

MockClasswriter("""
    |
    |package com.test
    |
    |class Example : Consumer<String> {
    |  override fun accept(value: String) {
    |    println("found: '$\value'")
    |  }
    |}
    """.trimMargin("|"))
    .writeToFile(codegenOutputFile)

确保它可以编译:

assertTrue(JvmCompile.exe(codegenOutputFile, compileOutputDir))

加载类作为接口(interface)实例

Initializer(compileOutputDir)
      .createInstance<Consumer<String>>("com.test.Example")
      ?.accept("Hello, world!")

输出将如预期:found: 'Hello, world!'

关于java - 如何在内存中运行编译 kotlin 文件的测试并检查结果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45888068/

相关文章:

android - AlarmManager 偶尔不触发警报

android - react native map : Markers image doesn't show using Custom Marker in react-native-maps

java - 当 Spring 发现两个同名的 bean 时,它会做什么?

java - 另一个 zip 重复条目

java - jdk的UseCompressedOops的作用是什么?

Java:输入/使用 "try-catch" block 的开销?

java - BeanToCsv不写入CSV文件

java - 追加到 JTextArea

java - 将字符串值从 spring bean 传递到 java 方法

java - 鉴于对象是任何类型的数组,您如何在 Java 中测试它是否为空?