Let's assume a controller object like this:
object Users extends Controller {
...
@ApiOperation(
httpMethod = "POST",
nickname = "authenticate",
value = "Authenticates an user",
notes = "Returns the JSON Web Token to be used in any subsequent request",
response = classOf[models.auth.api.Jwt])
def authenticate = SecuredAction[Users.type]("authenticate").async(parse.json) { implicit request =>
...
}
...
}
How do I get the annotation values of the authenticate
method at runtime? I've tried this:
def methodAnnotations[T: TypeTag]: Map[String, Map[String, Map[String, JavaArgument]]] = {
typeTag[T].tpe.declarations.collect { case m: MethodSymbol => m }.map { m =>
val methodName = m.name.toString
val annotations = m.annotations.map { a =>
val annotationName = a.tpe.typeSymbol.name.toString
val annotationArgs = a.javaArgs.map {
case (name, value) => name.toString -> value
}
annotationName -> annotationArgs
}.toMap
methodName -> annotations
}.toMap
}
methodAnnotations
returns the specified annotation for the specified method and is invoke like this:
val mAnnotations = methodAnnotations[T]
val nickname = mAnnotations("myMethodName")("MyAnnotationName")("myAnnotationMemberName").asInstanceOf[LiteralArgument].value.value.asInstanceOf[String]
The problem is that when I compile the code above I always get the following warnings:
type JavaArgument in trait Annotations is deprecated: Use `Annotation.tree` to inspect annotation arguments
method tpe in trait AnnotationApi is deprecated: Use `tree.tpe` instead
What's the correct way to get method annotations with scala 2.11?
If you can handle using Jackson, then I'd re-use its annotation processing functionality instead of using scala reflection.
object Test {
import com.fasterxml.jackson.databind.introspect.{AnnotatedClass, JacksonAnnotationIntrospector}
@ApiOperation(
httpMethod = "POST",
nickname = "authenticate",
value = "Authenticates an user",
notes = "Returns the JSON Web Token to be used in any subsequent request",
response = classOf[models.auth.api.Jwt])
def hasAnnotation() {}
def main(args: Array[String]): Unit = {
import scala.collection.JavaConversions._
val introspector = new JacksonAnnotationIntrospector
val ac = AnnotatedClass.construct(Test.getClass, introspector, null)
for (method <- ac.memberMethods()) {
val annotation = method.getAnnotation(classOf[ApiOperation])
if (annotation != null) {
println(s"${method.getFullName} -> ${annotation.nickname()}")
}
}
}
}
Probably the solution suggested by Nate is the most clean and efficient... but in my case it would require too much refactoring, so I've just decided to still use Scala reflection. Here is my solution:
package utils.common
import scala.reflect.runtime.universe._
/**
* Provides functionality for obtaining reflective information about
* classes and objects.
*/
object ReflectHelper {
/**
* Returns a `Map` from annotation names to annotation data for
* the specified type.
*
* @tparam T The type to get class annotations for.
* @return The class annotations for `T`.
*/
def classAnnotations[T: TypeTag]: Map[String, Map[String, Any]] = {
typeOf[T].typeSymbol.asClass.annotations.map { a =>
a.tree.tpe.typeSymbol.name.toString -> a.tree.children.withFilter {
_.productPrefix eq "AssignOrNamedArg"
}.map { tree =>
tree.productElement(0).toString -> tree.productElement(1)
}.toMap
}.toMap
}
/**
* Returns a `Map` from method names to a `Map` from annotation names to
* annotation data for the specified type.
*
* @tparam T The type to get method annotations for.
* @return The method annotations for `T`.
*/
def methodAnnotations[T: TypeTag]: Map[String, Map[String, Map[String, Any]]] = {
typeOf[T].decls.collect { case m: MethodSymbol => m }.withFilter {
_.annotations.length > 0
}.map { m =>
m.name.toString -> m.annotations.map { a =>
a.tree.tpe.typeSymbol.name.toString -> a.tree.children.withFilter {
_.productPrefix eq "AssignOrNamedArg"
}.map { tree =>
tree.productElement(0).toString -> tree.productElement(1)
}.toMap
}.toMap
}.toMap
}
}
I hope it helps.
来源:https://stackoverflow.com/questions/26897279/how-to-get-the-annotations-of-a-method-in-scala-2-11