我有一个类名和一个我知道类型参数的方法,我想通过反射来调用这个方法。
在java中我会做类似的事情:
Class.forName("foo").getMethod("name", ... type args...).invoke(null, ..args)
但是在Scala中,每当我尝试调用时,我都会得到一个null ref错误。
我使用的是scala 2.10.4
- 修改
我试过了:
$ scala
Welcome to Scala version 2.10.5 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_102).
Type in expressions to have them evaluated.
Type :help for more information.
scala> class Foo { def bar(x: Int) = x }
defined class Foo
scala> import scala.reflect.runtime.universe._
import scala.reflect.runtime.universe._
scala> val foo = new Foo
foo: Foo = Foo@2db7a79b
scala> runtimeMirror(getClass.getClassLoader).reflect(foo)
res0: reflect.runtime.universe.InstanceMirror = instance mirror for Foo@2db7a79b
scala> res0.symbol.typeSignature.member(newTermName("bar"))
res1: reflect.runtime.universe.Symbol = method bar
scala> res0.reflectMethod(res1.asMethodSymbol)(42)
<console>:15: error: value asMethodSymbol is not a member of reflect.runtime.universe.Symbol
res0.reflectMethod(res1.asMethodSymbol)(42)
^
作为"Dynamic" method invocation with new Scala reflection API的示例,它似乎不再起作用了
以下是对我要做的事情的测试:
object Test{
def run(): Boolean = true
}
class InvokeTests extends FlatSpec with Matchers {
"invoke" should "do" in {
import scala.reflect.runtime.universe._
val mirror = runtimeMirror(this.getClass.getClassLoader)
val moduleSymbol = mirror.moduleSymbol(Class.forName(Test.getClass.getName))
val reflected = mirror.reflect(moduleSymbol)
val methodName = reflected.symbol.typeSignature.member(newTermName("run"))
reflected.reflectMethod(methodName.asMethod)() shouldBe true
}
}
答案 0 :(得分:4)
参考scala doc reflection overview
// get runtime universe
val ru = scala.reflect.runtime.universe
// get runtime mirror
val rm = ru.runtimeMirror(getClass.getClassLoader)
// define class and companion object
class Boo{def hey(x: Int) = x}; object Boo{def hi(x: Int) = x*x}
// get instance mirror for companion object Boo
val instanceMirror = rm.reflect(Boo)
// get method symbol for the "hi" method in companion object
val methodSymbolHi = ru.typeOf[Boo.type].decl(ru.TermName("hi")).asMethod
// get method mirror for "hi" method
val methodHi = instanceMirror.reflectMethod(methodSymbolHi)
// invoke the method "hi"
methodHi(4) // 16
答案 1 :(得分:1)
对于Type
中只有Foo
(问题是foo
)的情况:
% scala
Welcome to Scala 2.13.1 (OpenJDK 64-Bit Server VM, Java 15-loom).
Type in expressions for evaluation. Or try :help.
scala> :paste
// Entering paste mode (ctrl-D to finish)
import scala.reflect.runtime.currentMirror
import scala.reflect.runtime.universe._
import scala.reflect.runtime.universe.definitions._
def f(tpe: Type): Unit = {
val m = currentMirror
val im = m.reflect(
m.reflectModule(tpe.typeSymbol.asClass.companion.asModule).instance
)
val method = tpe.companion.decl(TermName("name")).asMethod
val v = im.reflectMethod(method)("John", "Doe")
println(v)
}
// Exiting paste mode, now interpreting.
import scala.reflect.runtime.currentMirror
import scala.reflect.runtime.universe._
import scala.reflect.runtime.universe.definitions._
f: (tpe: reflect.runtime.universe.Type)Unit
scala> :paste
// Entering paste mode (ctrl-D to finish)
case class Foo()
case object Foo { def name(fn: String, ln: String): String = s"$fn $ln" }
// Exiting paste mode, now interpreting.
defined class Foo
defined object Foo
scala> f(typeOf[Foo])
John Doe
答案 2 :(得分:0)
下面的Scala 2.13.3示例代码在两种不同的情况下,通过找到引用相应示例类的伴随对象来调用通用方法apply
:
package spielwiese.reflection_versuche
object Structural_Typing_Companion_Object_Invoke_Testframe {
// Example 1
case class Person01(vorname: String, name: String)
object Person01 {
def apply(x: Integer): Person01 = new Person01(s"Prename_$x", s"Lastname_$x")
}
// Example 2
case class Person02(vorname: String, name: String)
object Person02 {
def apply(x: Integer): Person02 = new Person02(s"Prename_$x", s"Lastname_$x")
}
// Invocation demo:
import scala.reflect.runtime.{universe => ru}
def callGenericCompanionObjectMethod[T](implicit typetag: ru.TypeTag[T]) = {
val m = ru.runtimeMirror(getClass.getClassLoader)
val o1 = m.reflectModule(ru.typeOf[T].typeSymbol.companion.asModule).instance
val o2 = o1.asInstanceOf[{ def apply(x: Integer): T }] // "structural typing"
o2.apply(123)
}
def main(args: Array[String]): Unit = {
println(callGenericCompanionObjectMethod[Person01])
// prints: "Person01(Prename_123,Lastname_123)"
println(callGenericCompanionObjectMethod[Person02])
// prints: "Person02(Prename_123,Lastname_123)"
}
}