获取包对象

时间:2016-10-05 20:29:15

标签: scala reflection

我需要使用反射来获取在包对象上定义的字段。

package com.coryklein

package object kittens {
  val purr = "meow"
}

Mirrors documentation说:

  

Scala只有实例方法 - 对象的方法是对象实例的实例方法,可通过ModuleMirror.instance获取

甚至有一个慷慨的例子,使用反射来调用已定义的类x上的方法C

scala> class C { def x = 2 }
defined class C

scala> val im = m.reflect(new C)
im: reflect.runtime.universe.InstanceMirror = instance mirror for C@3442299e

scala> val methodX = typeOf[C].declaration(TermName("x")).asMethod
methodX: reflect.runtime.universe.MethodSymbol = method x

scala> val mm = im.reflectMethod(methodX)
mm: reflect.runtime.universe.MethodMirror = method mirror for C.x: scala.Int (bound to C@3442299e)

scala> mm()
res0: Any = 2

从这里开始,似乎不太难以使方法适应反映包对象上存在的字段。但是,包对象没有相应的类来从via反射中获取字段。

我能够获得术语符号:

val ts: TermSymbol = mirror.staticPackage("com.coryklein.kittens").info.decls
  .find(_.name.decodedName.toString == "purr").get.asTerm

但是在这一点上,我没有一个等同于im的实例镜像来反映这个字段。

如何通过Scala反射访问包对象purr中定义的kittens val?

1 个答案:

答案 0 :(得分:2)

这里的关键部分是找到实际模块,最终命名为com.coryklein.kittens.package$

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

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

scala> val runtimeMirror  = ru.runtimeMirror(getClass.getClassLoader)

runtimeMirror: reflect.runtime.universe.Mirror = JavaMirror with scala.tools.nsc.interpreter.IMain$TranslatingClassLoader@67ee3ed7 of type class scala.tools.nsc.interpreter.IMain$TranslatingClassLoader with classpath [(memory)] and parent being scala.reflect.internal.util.ScalaClassLoader$URLClassLoader@53b79b76 of type class scala.reflect.internal.util.ScalaClassLoader$URLClassLoader with classpath [file:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/resources.jar,file:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/rt.jar,file:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/jsse.jar,file:/Library/Java/JavaVirtualMachines/jdk1.8.0_111.jdk/Contents/Home/jre/lib/jce.jar,file:/Library/Jav...

scala> val moduleSymbol   = runtimeMirror.staticModule("com.coryklein.kittens.package$")

moduleSymbol: reflect.runtime.universe.ModuleSymbol = object package$

scala> val moduleMirror   = runtimeMirror.reflectModule(moduleSymbol)

moduleMirror: reflect.runtime.universe.ModuleMirror = module mirror for com.coryklein.kittens.package$ (bound to null)

scala> val moduleInstance = moduleMirror.instance

moduleInstance: Any = com.coryklein.kittens.package$@72d3f96

scala> val instanceMirror = runtimeMirror.reflect(moduleInstance)

instanceMirror: reflect.runtime.universe.InstanceMirror = instance mirror for com.coryklein.kittens.package$@72d3f96

scala> val fieldSymbol    = instanceMirror.symbol.info.member(ru.TermName("purr")).asTerm.accessed.asTerm

fieldSymbol: reflect.runtime.universe.TermSymbol = value purr

scala> val fieldMirror    = instanceMirror.reflectField(fieldSymbol)

fieldMirror: reflect.runtime.universe.FieldMirror = field mirror for private[this] val purr: java.lang.String (bound to com.coryklein.kittens.package$@72d3f96)

scala> fieldMirror.get

res0: Any = meow

scala>

我在我的target/scala-2.12/classes目录中找到了该模块的名称,并在这里和那里运行javap