【问题标题】:Calling a method from Annotation using reflection使用反射从 Annotation 调用方法
【发布时间】:2020-06-20 01:15:35
【问题描述】:

我有带有Size 注释的Sample

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 

问题:如何在Extractor类中调用方法getValue: T

【问题讨论】:

  • 对我来说看起来像 X/Y
  • @cchantep 听起来像是一个合理的运行时反思问题。

标签: scala reflection scala-reflect


【解决方案1】:

如果你喜欢注释

@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 类(或类似 case-class),那么您可以在编译时执行相同的操作

import shapeless.Annotations

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

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-03-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-30
  • 2012-08-08
相关资源
最近更新 更多