我在Scala中用.env.local
字段定义了一个注释类:
List
还有一些使用注释的类,例如:
class TestAnnotation(a: String, b: List[String]) extends StaticAnnotation
现在我想通过反射获取类注释值@TestAnnotation("test", List("b1", "b2"))
class TestA
和a
b
如何通过将import scala.reflect.runtime.universe
universe
.typeOf[TestA]
.typeSymbol
.annotations
.find(_.tree.tpe =:= universe.typeOf[TestAnnotation])
.map(_.tree).foreach(t => {
// Match Exceptions happen there! How to match the List fields?
val universe.Apply(_, universe.Literal(universe.Constant(a: String)) :: universe.Literal(universe.Constant(b: List[String])) :: Nil) = t
println(a)
println(b)
})
与List
匹配来解构t
来获取universe.Apply
值?
答案 0 :(得分:3)
最好的方法是一次迈出一步-再匹配一层,打印,检查我们到达那里,了解发生了什么,然后重复。
universe
.typeOf[TestA]
.typeSymbol
.annotations
.find(_.tree.tpe =:= universe.typeOf[TestAnnotation])
.map(_.tree).map(t => {
val universe.Apply(annotation, annotationArgs) = t
println(annotation)
println(annotationArgs)
println(annotationArgs.getClass.getName)
val List(aTree, bTree) = annotationArgs
println(aTree)
println(aTree.getClass.getName)
println(bTree)
println(bTree.getClass.getName)
val universe.Literal(universe.Constant(a: String)) = aTree
val universe.Apply(_, bArgsTree) = bTree
println(a)
println(a.getClass.getName) // we found A
println(bArgsTree)
println(bArgsTree.getClass.getName)
bArgsTree.foreach { elem =>
println(elem)
println(elem.getClass.getName)
}
val bs = bArgsTree.map { bTree =>
val universe.Literal(universe.Constant(b: String)) = bTree
println(b)
println(b.getClass.getName) // we found B
b
}
(a, bs)
})
new ammonite.$sess.cmd0.TestAnnotation
List("test", scala.collection.immutable.List.apply[String]("b1", "b2"))
scala.collection.immutable.$colon$colon
"test"
scala.reflect.internal.Trees$Literal
scala.collection.immutable.List.apply[String]("b1", "b2")
scala.reflect.internal.Trees$Apply
test
java.lang.String
List("b1", "b2")
scala.collection.immutable.$colon$colon
"b1"
scala.reflect.internal.Trees$Literal
"b2"
scala.reflect.internal.Trees$Literal
b1
java.lang.String
b2
java.lang.String
res10: Option[(String, List[String])] = Some(("test", List("b1", "b2")))
一旦弄清楚了它是如何工作的,我们可以将其重构为较短的形式:
universe
.typeOf[TestA]
.typeSymbol
.annotations
.find(_.tree.tpe =:= universe.typeOf[TestAnnotation])
.map(_.tree).map { case universe.Apply(_, List(universe.Literal(universe.Constant(a: String)), universe.Apply(_, bArgsTree))) =>
(a, bArgsTree.map { case universe.Literal(universe.Constant(b: String)) => b })
}
res21: Option[(String, List[String])] = Some(("test", List("b1", "b2")))
答案 1 :(得分:2)
您也可以使用准引用
universe
.typeOf[TestA]
.typeSymbol
.annotations
.find(_.tree.tpe =:= universe.typeOf[TestAnnotation])
.map(_.tree).map {
case q"new $_($a, $_($b1, $b2))" => println(s"a=$a, b1=$b1, b2=$b2")
}
//a="test", b1="b1", b2="b2"