首页 > 解决方案 > 使用反射从 Annotation 调用方法

问题描述

我有SampleSize注释的课

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

标签: scalareflectionscala-reflect

解决方案


如果你像这样注释

@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

推荐阅读