I am struggling to get a value from a scala annotation in a Play controller method.
I defined a class for the annotation:
case class Auth(perm: String) extends scala.annotation.StaticAnnotation
Then I am reading it in one of the Play's filters:
import scala.reflect.runtime.{universe => u}
val res = u.runtimeMirror(handlerDef.classLoader)
.classSymbol(Class.forName(handlerDef.controller))
.info
.decls
.find(_.name.toString == handlerDef.method)
.flatMap(_.asMethod.annotations.find(_.tree.tpe =:= u.typeOf[Auth]))
Now, I am getting Option[Annotation]
and when I println
it, it's: Some(Auth("test"))
- the value that I put in the annotation, so it's all good.
I can't wrap my head around how to actually convert Annotation
to my Auth
.
Help is appreciated, thanks!
Scaladoc of
scala.reflect.api.Annotations
sayshttps://github.com/scala/scala/blob/2.13.x/src/reflect/scala/reflect/api/Annotations.scala#L39-L42
You can use
Toolbox
to evaluate annotation treehttps://docs.scala-lang.org/overviews/reflection/symbols-trees-types.html#tree-creation-via-parse-on-toolboxes
Calling a method from Annotation using reflection
Or (e.g. if you want to depend on
scala-reflect
only and not onscala-compiler
) you can evaluate the tree manually:or
Notice that the tree will not match pattern
q"new com.example.Auth(${s: String})"
because annotation trees have different shape.By the way, with
rm.staticClass(...)
instead ofrm.classSymbol(Class.forName(...))
you can use Scala class name (e.g.org.example.App.MyClass
) instead of Java class name (e.g.org.example.App$MyClass
). Also you can tryscala.reflect.runtime.currentMirror
instead ofu.runtimeMirror(classLoader)
. Also.decls.find(_.name.toString == methodName)
can be replaced with.decl(u.TermName(methodName))
.Just in case, if you know types of class and annotation and method name at compile time then you can do the same using compile-time reflection