我编写了一个宏,将JSON
解析为匹配的case类。
def parse(jsonTree: JsValue): BaseType = macro parserImpl
def parserImpl(c: blackbox.Context)(jsonTree: c.Tree) = {
import c.universe._
val q"$json" = jsonTree
val cases = List("X", "Y").map { caseClassName =>
val caseClass = c.parse(caseClassName)
val reader = c.parse(s"JSONHelp.${caseClassName}_reads")
val y = cq"""$caseClassName => (($json "config").validate[$caseClass]($reader)).get"""
println(showCode(y))
y
}.toList
val r =
q"""
import play.api.libs.json._
import JSONHelp._
println($json)
($json "type").as[String] match { case ..$cases }
"""
println(showCode(r))
r
}
下面是它生成的代码(由最后一个println
打印):
{
import play.api.libs.json._;
import JSONHelp._;
println(NodeParser.this.json);
NodeParser.this.json.("type").as[String] match {
case "X" => NodeParser.this.json.("config").validate[X](JSONHelp.X_reads).get
case "Y" => NodeParser.this.json.("config").validate[Y](JSONHelp.Y_reads).get
}
}
包含宏定义的子项目的编译工作正常。但是,当我使用宏编译项目(使用sbt 0.13.11和scala 2.11.8)时,我得到以下错误:
java.lang.NullPointerException
at play.routes.compiler.RoutesCompiler$GeneratedSource$.unapply(RoutesCompiler.scala:37)
at play.sbt.routes.RoutesCompiler$$anonfun$11$$anonfun$apply$2.isDefinedAt(RoutesCompiler.scala:180)
at play.sbt.routes.RoutesCompiler$$anonfun$11$$anonfun$apply$2.isDefinedAt(RoutesCompiler.scala:179)
at scala.Option.collect(Option.scala:250)
at play.sbt.routes.RoutesCompiler$$anonfun$11.apply(RoutesCompiler.scala:179)
at play.sbt.routes.RoutesCompiler$$anonfun$11.apply(RoutesCompiler.scala:178)
我不是用户,但我看到它似乎想要一个源文件的树位置:
val routesPositionMapper: Position => Option[Position] = position => {
position.sourceFile collect {
case GeneratedSource(generatedSource) => {
典型使用atPos(pos)(tree)
。您可以假设传入的tree.pos
用于合成树。