0

在我的 Build.scala 中将应用程序拆分为子项目。

我需要针对一组子项目类运行编译任务;因为我无法在不将子项目本身制作成插件并依赖于它们的情况下静态导入子项目类,所以我求助于反射。

val fooTask = TaskKey[Unit]("foo", "Description...")
val foo = fooTask := {
  val classpath = Array("pathA", "pathB", "...")
  val sbtLoader = this.getClass.getClassLoader
  val appLoader: ClassLoader = URLClassLoader(classpath, sbtLoader)
  val mainClass = appLoader.loadClass("Foo")
  val mainMethod = mainClass.getMethod("main", classOf[Array[String]])
  try {
    mainMethod.invoke(new Object, Array(""))
  } 
  catch { 
    case e: InvocationTargetException => println(e.getCause)
  }
}

如果调用的方法中不涉及反射,一切正常,但不幸的是我也需要反射!FWIW,Foo 的用例是在编译时生成并写入静态文件,一组基于每个子项目控制器的 Play 框架 javascript 路由:

collection.map{ clazz=>
  clazz.getFields.map(_.get(null)).flatMap { c=>
   c.getClass.getDeclaredMethods.map(
     _.invoke(c).asInstanceOf[JavascriptReverseRoute]
   )
  }
}.flatten

它只java.lang.ClassNotFoundException: scala.reflect.ClassTag$存在于 Scala 2.10 中,适用于针对 2.10.2 编译的应用程序。然而,SBT 0.12.3 使用的是 Scala 2.9.2,而这肯定是纸牌反射屋崩溃的地方。

通过终端会话,我可以直接通过 Scala 2.10.2 运行所需的类,并且 javascript 路由生成得很好。但是,我不希望 Task 在每次编译时都启动一个新的 Scala 会话。

任何人都有解决方法的想法?完全卡住了,SBT 0.13 太新了,无法尝试构建 Play 及其所有基于 0.12 的插件。

谢谢

4

1 回答 1

1

您想使用不同的父类加载器。 this.getClass.getClassLoader包含用于运行 sbt 的 Scala 版本,正如您所描述的,这将导致链接错误。所以,从scalaInstance你的项目中获取加载器。此任务为scalaVersion您配置的 jar 和共享类加载器提供。

fooTask <<= scalaInstance map { si =>
   ...
   val appLoader: ClassLoader = URLClassLoader(classpath, si.loader)
   ...
}
于 2013-06-11T02:41:09.297 回答