Scala reflection to access all public fields at runtime

前端 未结 3 1692
栀梦
栀梦 2021-01-04 11:23

Given the following class hierarchy:

class A {
  val x = 3
  val y = 4
}

class B extends A {
  val z = 5
}

And say I have an instance of B

相关标签:
3条回答
  • 2021-01-04 11:38

    Here is a slightly other way to do it:

    scala> val i = 10
    i: Int = 10
    
    scala> val ru=scala.reflect.runtime.universe
    ru: scala.reflect.api.JavaUniverse = scala.reflect.runtime.JavaUniverse@2096fb9f
    
    scala> val m = ru.runtimeMirror(getClass.getClassLoader)
    m: ru.Mirror = JavaMirror with scala.tools.nsc.interpreter.IMain$TranslatingClassLoader@3ae5ce58 of type class scala.tools.nsc.interpreter.IMain$TranslatingClassLoader with classpath [(memory)] and parent being scala.tools.nsc.util.ScalaClassLoader$URLClassLoader@454e119d of type class scala.tools.nsc.util.ScalaClassLoader$URLClassLoader with classpath [file:/Library/Java/JavaVirtualMachines/jdk1.7.0_45.jdk/Contents/Home/jre/lib/resources.jar,file:/Library/Java/JavaVirtualMachines/jdk1.7.0_45.jdk/Contents/Home/jre/lib/rt.jar,file:/Library/Java/JavaVirtualMachines/jdk1.7.0_45.jdk/Contents/Home/jre/lib/jsse.jar,file:/Library/Java/JavaVirtualMachines/jdk1.7.0_45.jdk/Contents/Home/jre/lib/jce.jar,file:/Library/Java/JavaVirtualMachines/jdk1.7.0_45.jdk/Contents/Home/jre/lib/charsets.jar,file:...
    scala> val im=m.reflect(i)
    im: ru.InstanceMirror = instance mirror for 10
    
    scala> val is =im.symbol
    is: ru.ClassSymbol = class Int
    
    scala> val ims=is.toType.members
    ims: ru.MemberScope = Scopes(method getClass, constructor Int, method ##, method asInstanceOf, method isInstanceOf, method toString, method hashCode, method equals, method !=, method ==, method %, method %, method %, method %, method %, method %, method %, method /, method /, method /, method /, method /, method /, method /, method *, method *, method *, method *, method *, method *, method *, method -, method -, method -, method -, method -, method -, method -, method +, method +, method +, method +, method +, method +, method +, method ^, method ^, method ^, method ^, method ^, method &, method &, method &, method &, method &, method |, method |, method |, method |, method |, method >=, method >=, method >=, method >=, method >=, method >=, method >=, method >, method >, method >, met...
    scala> 
    

    ims can then be further filtered any way you like.

    0 讨论(0)
  • 2021-01-04 11:41

    In brief:

    import scala.reflect.runtime.universe._
    
    val a = new A
    val rm = scala.reflect.runtime.currentMirror
    val accessors = rm.classSymbol(a.getClass).toType.members.collect {
      case m: MethodSymbol if m.isGetter && m.isPublic => m 
    }
    val instanceMirror = rm.reflect(a)
    for(acc <- accessors)
      println(s"$a: ${instanceMirror.reflectMethod(acc).apply()}")
    
    0 讨论(0)
  • 2021-01-04 11:58

    You can you TypeTag to get an access:

    scala> import scala.reflect.runtime.universe._
    import scala.reflect.runtime.universe._
    
    scala> class A {
         |   val x = 3
         |   val y = 4
         | }
    defined class A
    
    scala> class B extends A {
         |   val z = 5
         | }
    defined class B
    
    scala> typeOf[B]
    res0: reflect.runtime.universe.Type = B
    

    Now you have two options: members which shows all members (even inherited ones) and declarations (only defined in the current class), e.g:

    scala> res0.declarations
    res2: reflect.runtime.universe.MemberScope = SynchronizedOps(constructor B, value z, value z)
    

    If you want to work with this field you need reflect them through InstanceMirror:

    scala> val b = new B
    b: B = B@6ebe10dd
    
    scala> val currentMirror = runtimeMirror(getClass.getClassLoader)
    .....
    
    scala> val bMir = currentMirror.reflect(b)
    bMir: reflect.runtime.universe.InstanceMirror = instance mirror for B@6ebe10dd
    

    Now you just need to get a Symbol you need, e.g you want to get a value of z varible:

    scala> val zt = typeOf[B].declaration("z": TermName).asMethod
    zt: reflect.runtime.universe.MethodSymbol = value z
    
    scala> bMir.reflectField(zt).get
    res20: Any = 5
    
    0 讨论(0)
提交回复
热议问题