运行时动态编译多个Scala类

Joh*_*ese 5 java reflection scala runtime scala-reflect

我知道我可以使用工具箱在 Scala 中编译单个“片段”,如下所示:

import scala.reflect.runtime.universe
import scala.tools.reflect.ToolBox

object Compiler {
  val tb = universe.runtimeMirror(getClass.getClassLoader).mkToolBox()

  def main(args: Array[String]): Unit = {
    tb.eval(tb.parse("""println("hello!")"""))
  }
}
Run Code Online (Sandbox Code Playgroud)

有什么方法可以编译不仅仅是“片段”,即相互引用的类?像这样:

import scala.reflect.runtime.universe
import scala.tools.reflect.ToolBox

object Compiler {
  private val tb = universe.runtimeMirror(getClass.getClassLoader).mkToolBox()

  val a: String =
    """
      |package pkg {
      |
      |class A {
      |def compute(): Int = 42
      |}}
    """.stripMargin

  val b: String =
    """
      |import pkg._
      |
      |class B {
      |def fun(): Unit = {
      |    new A().compute()
      |}
      |}
    """.stripMargin

  def main(args: Array[String]): Unit = {
    val compiledA = tb.parse(a)
    val compiledB = tb.parse(b)
    tb.eval(compiledB)
  }
}
Run Code Online (Sandbox Code Playgroud)

显然,我的代码段不起作用,因为我必须告诉工具箱如何以某种方式解析“A”:

线程“main” scala.tools.reflect.ToolBoxError 中的异常:反射编译失败:

未找到:类型 A

Dmy*_*tin 4

尝试

import scala.reflect.runtime.universe._
import scala.reflect.runtime.universe
import scala.tools.reflect.ToolBox

val tb = universe.runtimeMirror(getClass.getClassLoader).mkToolBox()

val a = q"""
          class A {
            def compute(): Int = 42
          }"""

val symbA = tb.define(a)

val b = q"""
          class B {
            def fun(): Unit = {
              new $symbA().compute()
            }
          }"""

tb.eval(b)
Run Code Online (Sandbox Code Playgroud)

https://github.com/scala/scala/blob/2.13.x/src/compiler/scala/tools/reflect/ToolBox.scala#L131-L138


如果情况比工具箱可以处理的情况更复杂,您始终可以手动运行编译器

import scala.reflect.internal.util.{AbstractFileClassLoader, BatchSourceFile}
import scala.reflect.io.{AbstractFile, VirtualDirectory}
import scala.tools.nsc.{Global, Settings}
import scala.reflect.runtime
import scala.reflect.runtime.universe
import scala.reflect.runtime.universe._

val a: String =
  """
    |package pkg {
    |
    |class A {
    |  def compute(): Int = 42
    |}}
""".stripMargin

val b: String =
  """
    |import pkg._
    |
    |class B {
    |  def fun(): Unit = {
    |    println(new A().compute())
    |  }
    |}
""".stripMargin

val directory = new VirtualDirectory("(memory)", None)
compileCode(List(a, b), List(), directory)
val runtimeMirror = createRuntimeMirror(directory, runtime.currentMirror)
val bInstance = instantiateClass("B", runtimeMirror)
runClassMethod("B", runtimeMirror, "fun", bInstance) // 42

def compileCode(sources: List[String], classpathDirectories: List[AbstractFile], outputDirectory: AbstractFile): Unit = {
  val settings = new Settings
  classpathDirectories.foreach(dir => settings.classpath.prepend(dir.toString))
  settings.outputDirs.setSingleOutput(outputDirectory)
  settings.usejavacp.value = true
  val global = new Global(settings)
  val files = sources.zipWithIndex.map { case (code, i) => new BatchSourceFile(s"(inline-$i)", code) }
  (new global.Run).compileSources(files)
}

def instantiateClass(className: String, runtimeMirror: Mirror, arguments: Any*): Any = {
  val classSymbol = runtimeMirror.staticClass(className)
  val classType = classSymbol.typeSignature
  val constructorSymbol = classType.decl(termNames.CONSTRUCTOR).asMethod
  val classMirror = runtimeMirror.reflectClass(classSymbol)
  val constructorMirror = classMirror.reflectConstructor(constructorSymbol)
  constructorMirror(arguments: _*)
}

def runClassMethod(className: String, runtimeMirror: Mirror, methodName: String, classInstance: Any, arguments: Any*): Any = {
  val classSymbol = runtimeMirror.staticClass(className)
  val classType = classSymbol.typeSignature
  val methodSymbol = classType.decl(TermName(methodName)).asMethod
  val instanceMirror = runtimeMirror.reflect(classInstance)
  val methodMirror = instanceMirror.reflectMethod(methodSymbol)
  methodMirror(arguments: _*)
}

//def runObjectMethod(objectName: String, runtimeMirror: Mirror, methodName: String, arguments: Any*): Any = {
//  val objectSymbol = runtimeMirror.staticModule(objectName)
//  val objectModuleMirror = runtimeMirror.reflectModule(objectSymbol)
//  val objectInstance = objectModuleMirror.instance
//  val objectType = objectSymbol.typeSignature
//  val methodSymbol = objectType.decl(TermName(methodName)).asMethod
//  val objectInstanceMirror = runtimeMirror.reflect(objectInstance)
//  val methodMirror = objectInstanceMirror.reflectMethod(methodSymbol)
//  methodMirror(arguments: _*)
//}

def createRuntimeMirror(directory: AbstractFile, parentMirror: Mirror): Mirror = {
  val classLoader = new AbstractFileClassLoader(directory, parentMirror.classLoader)
  universe.runtimeMirror(classLoader)
}
Run Code Online (Sandbox Code Playgroud)

动态解析flink map中的json

Scala 反射中的 Tensorflow

如何评估使用 InterfaceStability 注释的代码(因“涉及 InterfaceStability 类的非法循环引用”而失败)?