让我们假设一个像这样的控制器对象:
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获取方法注释的正确方法是什么?
答案 0 :(得分:1)
如果您可以使用Jackson处理,那么我将重新使用其注释处理功能,而不是使用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()}")
}
}
}
}
答案 1 :(得分: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
}
}
我希望它有所帮助。