使用反射从注解中调用方法

Calling a method from Annotation using reflection

我有 Sample class 和 Size 注释

case class Sample(
  attr: SomeTypeA
  @Size(value = 50)
  name: SomeTypeB)

Size 注释是 class 实现 AnnotationInterface

trait AnnotationInterface[T] {
  def getValue: T
}

class Size(value: Int) extends StaticAnnotation with AnnotationInterface[Int] {
    override def getValue: Int = value
}

我有 Extractor 负责使用反射 class 提取成员

class Extractor[A](implicit
    tt: TypeTag[A],
    ct: ClassTag[A]
) { ...extract class members using reflection... } 

然后我会像这样实例化提取器:

val extractor: Extractor[Sample] =
      new Extractor 

问题 : 如何调用 class Extractor 中的方法 getValue: T

如果你像

一样注释
@Size(50) name: String

而不是像

这样的元注释
@(Size @getter @setter @field)(50) name: String

然后 @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 并且可以将其设为 case class(或 case-class-喜欢)然后你可以在编译时做同样的事情

import shapeless.Annotations

Annotations[Size, Sample].apply() // None :: Some(Size(50)) :: HNil