2014-11-12 2 views
0

Предположит, объект контроллера, как это:Как получить аннотации методы в Scala 2,11

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 => 
    ... 
    } 

    ... 
} 

Как получить значение аннотаций методы authenticate во время выполнения? Я попытался это:

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 возвращает указанную аннотацию для указанного метода и вызывать так:

val mAnnotations = methodAnnotations[T] 
val nickname = mAnnotations("myMethodName")("MyAnnotationName")("myAnnotationMemberName").asInstanceOf[LiteralArgument].value.value.asInstanceOf[String] 

Проблема заключается в том, что, когда я скомпилировать код выше, я всегда получаю следующее предупреждения:

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 

Каков правильный способ получить аннотации методов с помощью scala 2.11?

ответ

1

Возможно решение, предложенное по Nate является наиболее чистым и эффективным ... но в моем случае это потребует слишком много рефакторинга, поэтому я просто решил по-прежнему использовать Scala отражение. Вот мое решение:

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 
    } 
} 

Надеюсь, это поможет.

1

Если вы можете обращаться с использованием Джексона, я бы снова использовал его функцию обработки аннотаций вместо использования scala-отражения.

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()}") 
     } 
    } 
    } 
} 
+0

Я попробую ... но могу ли я спросить, почему Джексон лучше, чем отражение scala? только для информации ;-) – j3d

+0

@ j3d Джексон широко используется, прочный, быстрый и чистый. Итак ... почему бы и нет, если он легко выполнит работу =)? Кроме того, API отражения Scala не дает вам доступа к параметрам аннотации без подглядывания (см. Http://stackoverflow.com/questions/26635223/scala-2-11-reflection-and-annotations-java-with-parameters/ 26637228 # 26637228). – Nate

+0

Я пробовал ... но это не работает для меня, потому что 'SecuredAction' должен принимать параметр типа ... и переданный тип должен быть« объектом », полученным из' Controller' ... – j3d

Смежные вопросы