Scala反射以按Universe获取列表字段值

时间:2020-06-24 08:22:58

标签: scala reflection scala-reflect

我在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值?

2 个答案:

答案 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"
相关问题