反射:将内部类的模块镜像混合为单个对象

时间:2013-08-05 10:36:01

标签: scala reflection inner-classes

在下面的场景中,当案例类被定义为内部类时,我无法找到案例类'伴随对象的apply方法:

case class Outer()

trait Foo {
  case class Inner()
}

object Bar extends Foo

到目前为止的方法:

import reflect.runtime.{currentMirror => cm, universe => ru}

def getApplyMethod[A: ru.TypeTag]: ru.MethodSymbol = {
  val sym     = ru.typeOf[A].typeSymbol
  val clazz   = sym.asClass
  val mod     = clazz.companionSymbol.asModule
  if (!mod.isStatic) println(s"Oh oh... $mod")  // and now?
  val im      = cm.reflect(cm.reflectModule(mod).instance)
  val ts      = im.symbol.typeSignature
  val mApply  = ts.member(ru.newTermName("apply")).asMethod
  mApply
}

getApplyMethod[Outer]
getApplyMethod[Bar.Inner]  // oh oh, detected, but what do to?

编译器的建议是:

object Inner is an inner module,
  use reflectModule on an InstanceMirror to obtain its ModuleMirror

那么我将如何解决这个问题,因为getApplyMethod唯一的信息是TypeTag[Bar.Inner]


注意通过在特征中混合Inner来引入此问题。如果我有

object Bar { case class Inner() }

它工作正常,Inner模块是“静态的”。

1 个答案:

答案 0 :(得分:4)

问题是,如果类型是路径相关的,TypeTag是否会对路径进行编码?

因为从实例开始工作很简单:

scala> trait Foo { case class Inner(i: Int) }
defined trait Foo

scala> object Bar extends Foo
defined object Bar

scala> import reflect.runtime._
import reflect.runtime._

scala> import universe._
import universe._

scala> currentMirror reflect Bar.Inner
res0: reflect.runtime.universe.InstanceMirror = instance mirror for Inner

scala> res0.symbol.typeSignature.member(newTermName("apply")).asMethod
res1: reflect.runtime.universe.MethodSymbol = method apply

scala> res0 reflectMethod res1
res3: reflect.runtime.universe.MethodMirror = method mirror for Foo.Inner.apply(i: scala.Int): Foo.this.Inner (bound to Inner)

scala> res3(7)
res4: Any = Inner(7)

从类型中手动获取封闭对象:

scala> typeOf[Bar.Inner]
res0: reflect.runtime.universe.Type = Bar.Inner

scala> val TypeRef(pre, sym, args) = res0
pre: reflect.runtime.universe.Type = Bar.type
sym: reflect.runtime.universe.Symbol = class Inner
args: List[reflect.runtime.universe.Type] = List()

scala> pre.typeSymbol.asClass.companionSymbol.asModule
res1: reflect.runtime.universe.ModuleSymbol = object Bar

scala> currentMirror reflectModule res1
res2: reflect.runtime.universe.ModuleMirror = module mirror for Bar (bound to null)

scala> res2.instance
res3: Any = Bar$@22a71ac

scala> currentMirror reflect res3
res4: reflect.runtime.universe.InstanceMirror = instance mirror for Bar$@22a71ac

scala> res4.symbol
res5: reflect.runtime.universe.ClassSymbol = object Bar

然后向下钻取到Inner

scala> res5.typeSignature.member(newTermName("Inner"))
res7: reflect.runtime.universe.Symbol = object Inner

scala> res7.asModule
res9: reflect.runtime.universe.ModuleSymbol = object Inner

scala> res9.moduleClass
res10: reflect.runtime.universe.Symbol = object Inner

scala> res10.typeSignature
res11: reflect.runtime.universe.Type = 
scala.runtime.AbstractFunction1[scala.Int,Foo.this.Inner]
        with scala.Serializable {
  def <init>(): Foo.this.Inner.type
  final override def toString(): java.lang.String
  case def apply(i: scala.Int): Foo.this.Inner
  case def unapply(x$0: Foo.this.Inner): scala.Option[scala.Int]
  private def readResolve(): java.lang.Object
}

scala> res11.member(newTermName("apply"))
res12: reflect.runtime.universe.Symbol = method apply

或使用sym

scala> res5.typeSignature.member(sym.name)
res16: reflect.runtime.universe.Symbol = class Inner

scala> res16.asClass.companionSymbol
res17: reflect.runtime.universe.Symbol = object Inner

scala> res17.typeSignature.member(newTermName("apply"))
res18: reflect.runtime.universe.Symbol = method apply

使用它:

scala> res4 reflectModule res9
res20: reflect.runtime.universe.ModuleMirror = module mirror for Foo.Inner (bound to Bar$@22a71ac)

scala> res20.instance
res22: Any = Inner

scala> currentMirror reflect res22
res23: reflect.runtime.universe.InstanceMirror = instance mirror for Inner

scala> res23 reflectMethod res18.asMethod
res24: reflect.runtime.universe.MethodMirror = method mirror for Foo.Inner.apply(i: scala.Int): Foo.this.Inner (bound to Inner)

scala> res24(7)
res25: Any = Inner(7)