问题描述
我有一个Java Method
实例,该实例代表具有Scala注释(扩展了StaticAnnotation
)的Scala函数。我知道我可以使用Method.getAnnotation(classOf[SomeJavaAnnotation])
来获取Java注释,但这将为Scala注释返回null
。
如何从中获取Scala注释?看来我需要先将其转换为Scala MethodSymbol
,但是我没有看到一种明显的方法来做到这一点,而且我只看到了展示如何进行反方向转换的资源(来自Scala {{1} }到Java MethodSymbol
)。
解决方法
Scala批注对于Java反射是不可见的。
任何一个
-
使用Java批注(具有运行时保留策略),则它们对于Java反射将是可见的,或者
-
使用Scala reflection,它可以看到Scala注释。
这是将java.lang.reflect.Method
转换为scala.reflect.runtime.universe.MethodSymbol
的方式
import java.lang.reflect.Method
import scala.reflect.runtime
import scala.reflect.runtime.universe._
def methodToMethodSymbol(method: Method): MethodSymbol = {
val runtimeMirror = runtime.currentMirror
val classSymbol = runtimeMirror.classSymbol(method.getDeclaringClass)
classSymbol.typeSignature.decl(TermName(method.getName)).asMethod // (*)
}
如果该方法有重载版本,则必须替换 行(*) 与
classSymbol.typeSignature.decl(TermName(method.getName)).alternatives.find(
_.asMethod.paramLists.flatten.map(_.typeSignature.erasure.typeSymbol.asClass) ==
method.getParameterTypes.map(runtimeMirror.classSymbol).toList
).get.asMethod
另一种实现方式:
def methodToMethodSymbol(method: Method): MethodSymbol = {
val runtimeMirror = runtime.currentMirror
val castedRuntimeMirror = runtimeMirror.asInstanceOf[{
def methodToScala(meth: Method): scala.reflect.internal.Symbols#MethodSymbol
}]
castedRuntimeMirror.methodToScala(method).asInstanceOf[MethodSymbol]
}
测试:
class myAnnotation extends StaticAnnotation
class MyClass {
@myAnnotation
def myMethod(i: Int): Unit = ()
}
val clazz = classOf[MyClass]
val method = clazz.getMethod("myMethod",classOf[Int])
val methodSymbol = methodToMethodSymbol(method) // method myMethod
methodSymbol.annotations // List(myAnnotation)
以防万一,这是将scala.reflect.runtime.universe.MethodSymbol
反向转换为java.lang.reflect.Method
def methodSymbolToMethod(methodSymbol: MethodSymbol): Method = {
val runtimeMirror = runtime.currentMirror
val classSymbol = methodSymbol.owner.asClass
val clazz = runtimeMirror.runtimeClass(classSymbol)
val paramClasses = methodSymbol.paramLists.flatten.map(paramSymbol =>
runtimeMirror.runtimeClass(paramSymbol.typeSignature.erasure)
)
clazz.getMethod(methodSymbol.name.toString,paramClasses: _*)
}
另一种实现方式:
def methodSymbolToMethod(methodSymbol: MethodSymbol): Method = {
type InternalMethodSymbol = scala.reflect.internal.Symbols#MethodSymbol
val runtimeMirror = runtime.currentMirror
val castedRuntimeMirror = runtimeMirror.asInstanceOf[{
def methodToJava(sym: InternalMethodSymbol): Method
}]
castedRuntimeMirror.methodToJava(
methodSymbol.asInstanceOf[InternalMethodSymbol]
)
}
Get a java.lang.reflect.Method from a reflect.runtime.universe.MethodSymbol