복붙노트

[SCALA] 동적 스칼라 2.11 런타임에 스칼라 클래스 파일을 컴파일

SCALA

동적 스칼라 2.11 런타임에 스칼라 클래스 파일을 컴파일

나는 스칼라 2.10의 작품 스칼라에서 런타임에 외부 클래스를 컴파일하는 다음 코드가

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

그러나 getInterpreterClassLoader 방법으로 더 이상 작동 위의 scala.tools.nsc.interpreter.IMain에서 제거되었습니다. 또한, AbstractFileClassLoader 이동 및 사용되지 않습니다. 더 이상 외부 패키지에서 클래스 로더에 (때문에) findClass 메소드를 호출 할 수 없습니다.

스칼라 2.11에서 위의 작업을 수행하기 위해 권장되는 방법은 무엇입니까? 감사!

해결법

  1. ==============================

    1.당신의 목표는 런타임에서 외부 스칼라 클래스를 실행하는 경우, 내가 scala.tools.reflect.ToolBox와 평가를 사용하는 것이 좋습니다 것 (그것은 REPL에 포함되어 있지만, 일반적인 사용을 위해 당신은 스칼라 - reflect.jar를 추가해야한다) :

    당신의 목표는 런타임에서 외부 스칼라 클래스를 실행하는 경우, 내가 scala.tools.reflect.ToolBox와 평가를 사용하는 것이 좋습니다 것 (그것은 REPL에 포함되어 있지만, 일반적인 사용을 위해 당신은 스칼라 - 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

  2. from https://stackoverflow.com/questions/39137175/dynamically-compiling-scala-class-files-at-runtime-in-scala-2-11 by cc-by-sa and MIT license