获取 Java 方法的 Scala 注解

huangapple go评论79阅读模式
英文:

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

https://stackoverflow.com/questions/16787163/get-a-java-lang-reflect-method-from-a-reflect-runtime-universe-methodsymbol

英文:

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

https://stackoverflow.com/questions/16787163/get-a-java-lang-reflect-method-from-a-reflect-runtime-universe-methodsymbol

huangapple
  • 本文由 发表于 2020年10月16日 01:59:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/64377276.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定