问题
I have Sample
class with Size
annotation
case class Sample(
attr: SomeTypeA
@Size(value = 50)
name: SomeTypeB)
This Size
annotation is a class that implements AnnotationInterface
trait AnnotationInterface[T] {
def getValue: T
}
class Size(value: Int) extends StaticAnnotation with AnnotationInterface[Int] {
override def getValue: Int = value
}
And I have Extractor
which is responsible for extracting class members using reflection
class Extractor[A](implicit
tt: TypeTag[A],
ct: ClassTag[A]
) { ...extract class members using reflection... }
Then I would instantiate the extractor like:
val extractor: Extractor[Sample] =
new Extractor
Question : How can I call the method getValue: T
inside the class Extractor
?
回答1:
If you annotate like
@Size(50) name: String
rather than with meta-annotations like
@(Size @getter @setter @field)(50) name: String
then @Size
remains only on constructor parameter, not field, getter or setter. So you need to use constructor of A
.
Try
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
}
}
if you need the value
or
import scala.tools.reflect.ToolBox
val tb = universe.runtimeMirror(getClass.getClassLoader).mkToolBox()
tb.eval(tb.untypecheck(annotationTree)).asInstanceOf[Size].getValue //50
if you really want to call getValue
.
By the way, if you have access to Size
and can make it a case class (or case-class-like) then you can do the same mostly at compile time
import shapeless.Annotations
Annotations[Size, Sample].apply() // None :: Some(Size(50)) :: HNil
来源:https://stackoverflow.com/questions/62343008/calling-a-method-from-annotation-using-reflection