加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

在Scala 2.11中在运行时动态编译scala类文件

发布时间:2020-12-16 09:26:23 所属栏目:安全 来源:网络整理
导读:我有以下代码在Scala 2.10中工作,以在Scala中运行时编译外部类 /** * 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
我有以下代码在Scala 2.10中工作,以在Scala中运行时编译外部类

/**
  * 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()
}

然后在其他地方,我可以使用类加载器引用来实例化类,例如

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)

但是,由于已从scala.tools.nsc.interpreter.IMain中删除了getInterpreterClassLoader方法,因此上述操作不再有效.此外,AbstractFileClassLoader已被移动和弃用.不再允许从外部包调用类加载器中的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

http://docs.scala-lang.org/overviews/quasiquotes/intro.html

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读