How to do Reflection to get the value of a field by its string name and its original type

When you try to get an object field by its string name, the value is returned, and not by the scala rule. AT:

import scala.language.reflectiveCalls
import scala.language.implicitConversions

case class Intity(flag: Boolean, id: Int, name: String)
val inty =  Intity(false, 123, "blue")

implicit def reflect(r: AnyRef) = new {
  def get(n:String) = {
    val c = r.getClass.getDeclaredField(n)
    c.setAccessible(true); c}
  def getVal(n: String) = get(n).get(r)
  def getType (n:String) = get(n).getType
 }

then using this

inty.getType("flag")     // res0: Class[_] = boolean  --not Boolean
inty.getVal("id")        // res1: Object = 123    --Object not Int

Any efficient way to accomplish the above implementation?

+4
source share
2 answers

Not sure how to return different types from the same function. But you can infer the correct type of any class attribute using scala to reflect api (s).

import scala.reflect.runtime.{universe => ru}
implicit class ForAnyInstance[T: ru.TypeTag](i: T)(implicit c: scala.reflect.ClassTag[T]) {

    /* a mirror sets a scope of the entities on which we have reflective access */
    val mirror = ru.runtimeMirror(getClass.getClassLoader)

    /* here we get an instance mirror to reflect on an instance */
    val im = ru.runtimeMirror(i.getClass.getClassLoader)

    def fieldInfo(name: String) = {
      ru.typeOf[T].members.filter(!_.isMethod).filter(_.name.decoded.trim.equals(name)).foreach(s => {
        val fieldValue = im.reflect(i).reflectField(s.asTerm).get

        /* typeSignature contains runtime type information about a Symbol */
        s.typeSignature match {
          case x if x =:= ru.typeOf[String] => /* do something */
          case x if x =:= ru.typeOf[Int] => /* do something */
          case x if x =:= ru.typeOf[Boolean] => /* do something */
        }
      })
    }
}

And then call it like:

case class Entity(flag: Boolean, id: Int, name: String)
val e = Entity(false, 123, "blue")
e.fieldInfo("flag")
e.fieldInfo("id")
+5
source

You can do something similar at compile time with formless.

scala> import shapeless._
import shapeless._

scala> val inty = Intity(false, 123, "blue")
inty: Intity = Intity(false,123,blue)        

scala> val intyGen = LabelledGeneric[Intity].to(inty)
intyGen: shapeless.::[Boolean with shapeless.labelled.KeyTag[Symbol with shapeless.tag.Tagged[String("flag")],Boolean],shapeless.::[Int with shapeless.labelled.KeyTag[Symbol with shapeless.tag.Tagged[String("id")],Int],shapeless.::[String with shapeless.labelled.KeyTag[Symbol with shapeless.tag.Tagged[String("name")],String],shapeless.HNil]]] = false :: 123 :: blue :: HNil

scala> import shapeless.record._
import shapeless.record._

scala> intyGen.get('flag)
res10: Boolean = false

scala> intyGen.get(Symbol("id"))
res11: Int = 123
+1
source

Source: https://habr.com/ru/post/1661990/


All Articles