使用scala中的反射进行动态对象方法调用

时间:2014-07-25 09:57:38

标签: scala reflection

我希望创建一种根据scala中的模板ID动态调用逻辑的方法。因此模板id 1调用逻辑a,模板id 2调用逻辑b等。逻辑将是多样的但具有相同的输入/输出。此外,不同模板ID的数量将达到数千个,并且不会提前知道,因此松耦合感觉还有很长的路要走。

我已经开始使用scala 2.11.1开始查看反射,并且当我知道要提前使用的逻辑但是没有找到动态使用反射的正确方法时,可以静态地使用反射,所以对于传入模板ID 2的示例将调用逻辑b。

下面是一个简短的示例,展示了静态版本的工作原理以及我到目前为止动态版本的骨架。

package thePackage

import scala.reflect.runtime.{universe => ru}

trait theTrait { def theMethod(x: String): Unit }

// the different logic held in different objects
object object1 extends theTrait {
  def theMethod(x: String) = { println("a " + x ) }
}

object object2 extends theTrait { 
  def theMethod(x: String) = { println("b " + x ) }
}

object object3 extends theTrait {
  def theMethod(x: String) = { println("c " + x ) }
}

// run static/dynamic reflection methods
object ReflectionTest {

  // "static" invocation calling object1.theMethod
  def staticInvocation() = {
    val m = ru.runtimeMirror(getClass.getClassLoader)
    val im = m.reflect(thePackage.object1)
    val method = ru.typeOf[thePackage.object1.type]
                   .decl(ru.TermName("theMethod")).asMethod
    val methodRun = im.reflectMethod(method)
    methodRun("test")
  }

  staticInvocation

  // "dynamic" invocation using integer to call different methods
  def dynamicInvocation( y: Integer) = {
    val m = ru.runtimeMirror(getClass.getClassLoader)
    val module = m.staticModule("thePackage.object" + y)
    val im = m.reflectModule(module)

    //  stuck... static approach does not work here

  }

  dynamicInvocation(1)
  dynamicInvocation(2)
  dynamicInvocation(3)

}

需要添加/更改为dynamicInvocation方法才能使其工作,或者我应该使用不同的方法?

2 个答案:

答案 0 :(得分:5)

您需要为模块获取一个实例镜像,您可以在其上反映该方法。

def dynamicInvocation( y: Integer) = {
  val m = ru.runtimeMirror(getClass.getClassLoader)
  val module = m.staticModule("thePackage.object" + y)
  val im = m.reflectModule(module)
  val method = im.symbol.info.decl(ru.TermName("theMethod")).asMethod

  val objMirror = m.reflect(im.instance)
  objMirror.reflectMethod(method)("test")
}

答案 1 :(得分:1)

上面的解决方案中的TermName方法似乎已被newTermName取代,而且info.decl似乎也不起作用。以下线为我工作

val method = im.symbol.typeSignature.member(ru.newTermName("testMethod")).asMethod