2013-08-05 2 views
1

У меня возникли проблемы с поиском 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 модуль «статический».

+0

возможно дубликат [Получить экземпляр объекта компаньоном внутреннего Modul с отражением API Scala] (http://stackoverflow.com/questions/16440124/get-the -companion-object-instance-of-a-inner-modul-with-the-scala-reflection-api) – senia

+0

@senia Я видел этот вопрос. Но (а) у вас есть фактическое значение, чтобы взять зеркало экземпляра, (b) оно не охватывает общий случай, когда могут возникать как статические, так и нестатические. –

ответ

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 = [email protected] 

scala> currentMirror reflect res3 
res4: reflect.runtime.universe.InstanceMirror = instance mirror for [email protected] 

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 [email protected]) 

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) 
+0

Спасибо. Откуда появился конструктор «TermName»? Для меня (Scala 2.10.2) работает только 'newTermName' (в' universe'). –

+0

@ 0__ да, он переименован в 2.11. –

Смежные вопросы