反射:从内部类获取模块镜像混合成单例对象
在以下情况下,如果将案例类定义为内部类,则无法找到案例类的伴随对象的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
模块是“静态”的。
问题是,如果类型是路径依赖的,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)
链接地址: http://www.djcxy.com/p/76525.html
上一篇: Reflection: Getting module mirror from inner class mixed into a singleton object
下一篇: Finding enclosing instance (if any) by Scala reflection