scala – 获取包对象上的字段的FieldMirror

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

package com.coryklein

package object kittens {
  val purr = "meow"
}

Mirrors documentation说:

Scala only has instance methods– methods of objects are instance methods of object instances, obtainable via ModuleMirror.instance

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

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?

最佳答案 这里的关键部分是找到实际的模块,最终命名为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.

点赞