微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

从Java方法获取Scala批注

如何解决从Java方法获取Scala批注

我有一个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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。