scala - 使用反射从 Annotation 调用方法
问题描述
我有Sample
带Size
注释的课
case class Sample(
attr: SomeTypeA
@Size(value = 50)
name: SomeTypeB)
这个Size
注解是一个实现的类AnnotationInterface
trait AnnotationInterface[T] {
def getValue: T
}
class Size(value: Int) extends StaticAnnotation with AnnotationInterface[Int] {
override def getValue: Int = value
}
我Extractor
负责使用反射提取类成员
class Extractor[A](implicit
tt: TypeTag[A],
ct: ClassTag[A]
) { ...extract class members using reflection... }
然后我会像这样实例化提取器:
val extractor: Extractor[Sample] =
new Extractor
问题:如何getValue: T
在类中调用方法Extractor
?
解决方案
如果你像这样注释
@Size(50) name: String
而不是像元注释
@(Size @getter @setter @field)(50) name: String
then@Size
仅保留在构造函数参数上,而不是字段、getter 或 setter。所以你需要使用A
.
尝试
class Extractor[A](implicit
tt: TypeTag[A],
ct: ClassTag[A]
) {
val annotationTree = typeOf[A]
.decl(termNames.CONSTRUCTOR).asMethod
.paramLists.flatten
.flatMap(_.annotations)
.map(_.tree)
.filter(_.tpe =:= typeOf[Size])
.head
annotationTree match {
case q"new $_($value)" => println(value) //50
}
}
如果你需要value
或
import scala.tools.reflect.ToolBox
val tb = universe.runtimeMirror(getClass.getClassLoader).mkToolBox()
tb.eval(tb.untypecheck(annotationTree)).asInstanceOf[Size].getValue //50
如果你真的想打电话getValue
。
顺便说一句,如果您可以访问Size
并且可以将其设为案例类(或类似案例类),那么您可以在编译时做同样的事情
import shapeless.Annotations
Annotations[Size, Sample].apply() // None :: Some(Size(50)) :: HNil