英文:
Get Scala annotation from Java Method
问题
我有一个 Java Method
实例,表示带有 Scala 注解(扩展了 StaticAnnotation
)的 Scala 函数。我知道我可以使用 Method.getAnnotation(classOf[SomeJavaAnnotation])
来获取一个 Java 注解,但是对于 Scala 注解,这会返回 null
。
如何从中获取 Scala 注解?似乎我需要先将其转换为 Scala MethodSymbol
,但我没有看到明显的方法来做到这一点,我只看到一些资源展示如何实现相反的过程(从 Scala MethodSymbol
到 Java Method
)。
英文:
I have an instance of Java Method
that represents a Scala function with a Scala annotation (that extends StaticAnnotation
). I know I can use Method.getAnnotation(classOf[SomeJavaAnnotation])
to get a Java annotation, but this returns null
for Scala annotations.
How can I get the Scala annotation from this? It seems I need to convert it to a Scala MethodSymbol
first, but I don't see an obvious way to do that and I've only seen resources showing how to go the other way (from Scala MethodSymbol
to Java Method
).
答案1
得分: 1
Scala注解在Java反射中是不可见的。
要么
-
使用Java注解(带有运行时保留策略),然后它们将对Java反射可见,或者
-
使用Scala反射,它可以看到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]
)
}
英文:
Scala annotations are invisible for Java reflection.
Either
-
use Java annotations (with runtime retention policy), then they will be visible for Java reflection, or
-
use Scala reflection, it can see Scala annotations.
This is how java.lang.reflect.Method
can be converted into 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 // (*)
}
If there are overloaded versions of the method, you'll have to replace
the line (*)
with
classSymbol.typeSignature.decl(TermName(method.getName)).alternatives.find(
_.asMethod.paramLists.flatten.map(_.typeSignature.erasure.typeSymbol.asClass) ==
method.getParameterTypes.map(runtimeMirror.classSymbol).toList
).get.asMethod
Another implementation:
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]
}
Testing:
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)
Just in case, here is reverse conversion of scala.reflect.runtime.universe.MethodSymbol
into 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: _*)
}
Another implementation:
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]
)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论