在 Scala 2.11 运行时动态编译 scala class 文件
Dynamically compiling scala class files at runtime in Scala 2.11
我有以下代码可在 Scala 2.10 中运行以在运行时在 Scala 中编译外部 classes
/**
* Compile scala files and keep them loaded in memory
* @param classDir Directory storing the generated scala files
* @throws IOException if there is problem reading the source files
* @return Classloader that contains the compiled external classes
*/
@throws[IOException]
def compileFiles(classDir: String): AbstractFileClassLoader = {
val files = recursiveListFiles(new File(classDir))
.filter(_.getName.endsWith("scala"))
println("Loaded files: \n" + files.mkString("[", ",\n", "]"))
val settings: GenericRunnerSettings = new GenericRunnerSettings(err => println("Interpretor error: " + err))
settings.usejavacp.value = true
val interpreter: IMain = new IMain(settings)
files.foreach(f => {
interpreter.compileSources(new BatchSourceFile(AbstractFile.getFile(f)))
})
interpreter.getInterpreterClassLoader()
}
然后在其他地方,我可以使用 classloader 引用来实例化 classes,例如
val personClass = classLoader.findClass("com.example.dynacsv.PersonData")
val ctor = personClass.getDeclaredConstructors()(0)
val instance = ctor.newInstance("Mr", "John", "Doe", 25: java.lang.Integer, 165: java.lang.Integer, 1: java.lang.Integer)
println("Instantiated class: " + instance.getClass.getCanonicalName)
println(instance.toString)
然而,上述方法不再有效,因为 getInterpreterClassLoader
方法已从 scala.tools.nsc.interpreter.IMain
中删除。此外,AbstractFileClassLoader 已被移动和弃用。不再允许从外部包调用 class 加载程序中的 findClass
方法。
在 Scala 2.11 中执行上述操作的推荐方法是什么?谢谢!
如果你的目标是在 运行 时间内 运行 外部 scala 类,我建议将 eval 与 scala.tools.reflect.ToolBox
一起使用(它包含在 REPL 中,但是对于正常使用,您必须添加 scala-reflect.jar):
import scala.reflect.runtime.universe
import scala.tools.reflect.ToolBox
val tb = universe.runtimeMirror(getClass.getClassLoader).mkToolBox()
tb.eval(tb.parse("""println("hello!")"""))
您也可以编译文件,使用tb.compile
。
修改示例:假设你有外部文件
class PersonData() {
val field = 42
}
scala.reflect.classTag[PersonData].runtimeClass
你也是
val clazz = tb.compile(tb.parse(src))().asInstanceOf[Class[_]]
val ctor = clazz.getDeclaredConstructors()(0)
val instance = ctor.newInstance()
其他可能性(几乎)是无限的,您可以获得完整的树 AST 并根据需要使用它:
showRaw(tb.parse(src)) // this is AST of external file sources
// this is quasiquote
val q"""
class $name {
..$stats
}
scala.reflect.classTag[PersonData].runtimeClass
""" = tb.parse(src)
// name: reflect.runtime.universe.TypeName = PersonData
// stats: List[reflect.runtime.universe.Tree] = List(val field = 42)
println(name) // PersonData
有关这些技巧,请参阅官方文档:
http://docs.scala-lang.org/overviews/reflection/symbols-trees-types.html
我有以下代码可在 Scala 2.10 中运行以在运行时在 Scala 中编译外部 classes
/**
* Compile scala files and keep them loaded in memory
* @param classDir Directory storing the generated scala files
* @throws IOException if there is problem reading the source files
* @return Classloader that contains the compiled external classes
*/
@throws[IOException]
def compileFiles(classDir: String): AbstractFileClassLoader = {
val files = recursiveListFiles(new File(classDir))
.filter(_.getName.endsWith("scala"))
println("Loaded files: \n" + files.mkString("[", ",\n", "]"))
val settings: GenericRunnerSettings = new GenericRunnerSettings(err => println("Interpretor error: " + err))
settings.usejavacp.value = true
val interpreter: IMain = new IMain(settings)
files.foreach(f => {
interpreter.compileSources(new BatchSourceFile(AbstractFile.getFile(f)))
})
interpreter.getInterpreterClassLoader()
}
然后在其他地方,我可以使用 classloader 引用来实例化 classes,例如
val personClass = classLoader.findClass("com.example.dynacsv.PersonData")
val ctor = personClass.getDeclaredConstructors()(0)
val instance = ctor.newInstance("Mr", "John", "Doe", 25: java.lang.Integer, 165: java.lang.Integer, 1: java.lang.Integer)
println("Instantiated class: " + instance.getClass.getCanonicalName)
println(instance.toString)
然而,上述方法不再有效,因为 getInterpreterClassLoader
方法已从 scala.tools.nsc.interpreter.IMain
中删除。此外,AbstractFileClassLoader 已被移动和弃用。不再允许从外部包调用 class 加载程序中的 findClass
方法。
在 Scala 2.11 中执行上述操作的推荐方法是什么?谢谢!
如果你的目标是在 运行 时间内 运行 外部 scala 类,我建议将 eval 与 scala.tools.reflect.ToolBox
一起使用(它包含在 REPL 中,但是对于正常使用,您必须添加 scala-reflect.jar):
import scala.reflect.runtime.universe
import scala.tools.reflect.ToolBox
val tb = universe.runtimeMirror(getClass.getClassLoader).mkToolBox()
tb.eval(tb.parse("""println("hello!")"""))
您也可以编译文件,使用tb.compile
。
修改示例:假设你有外部文件
class PersonData() {
val field = 42
}
scala.reflect.classTag[PersonData].runtimeClass
你也是
val clazz = tb.compile(tb.parse(src))().asInstanceOf[Class[_]]
val ctor = clazz.getDeclaredConstructors()(0)
val instance = ctor.newInstance()
其他可能性(几乎)是无限的,您可以获得完整的树 AST 并根据需要使用它:
showRaw(tb.parse(src)) // this is AST of external file sources
// this is quasiquote
val q"""
class $name {
..$stats
}
scala.reflect.classTag[PersonData].runtimeClass
""" = tb.parse(src)
// name: reflect.runtime.universe.TypeName = PersonData
// stats: List[reflect.runtime.universe.Tree] = List(val field = 42)
println(name) // PersonData
有关这些技巧,请参阅官方文档:
http://docs.scala-lang.org/overviews/reflection/symbols-trees-types.html