Scala 2.10 reflection, how do I extract the field values from a case class, i.e. field list from case class

戏子无情 提交于 2019-12-17 10:26:47

问题


How can I extract the field values from a case class in scala using the new reflection model in scala 2.10? For example, using the below doesn't pull out the field methods

  def getMethods[T:TypeTag](t:T) =  typeOf[T].members.collect {
    case m:MethodSymbol => m
  }

I plan to pump them into

  for {field <- fields} {
    currentMirror.reflect(caseClass).reflectField(field).get
  }

回答1:


MethodSymbol has an isCaseAccessor method that allows you to do precisely this:

def getMethods[T: TypeTag] = typeOf[T].members.collect {
  case m: MethodSymbol if m.isCaseAccessor => m
}.toList

Now you can write the following:

scala> case class Person(name: String, age: Int)
defined class Person

scala> getMethods[Person]
res1: List[reflect.runtime.universe.MethodSymbol] = List(value age, value name)

And you get only the method symbols you want.

If you just want the actual field name (not the value prefix) and you want them in the same order then:

def getMethods[T: TypeTag]: List[String] =
  typeOf[T].members.sorted.collect {
    case m: MethodSymbol if m.isCaseAccessor => m.name.toString
  }



回答2:


If you want to get fancier you can get them in order by inspecting the constructor symbol. This code works even if the case class type in question has multiple constructors defined.

  import scala.collection.immutable.ListMap
  import scala.reflect.runtime.universe._

  /**
    * Returns a map from formal parameter names to types, containing one
    * mapping for each constructor argument.  The resulting map (a ListMap)
    * preserves the order of the primary constructor's parameter list.
    */
  def caseClassParamsOf[T: TypeTag]: ListMap[String, Type] = {
    val tpe = typeOf[T]
    val constructorSymbol = tpe.decl(termNames.CONSTRUCTOR)
    val defaultConstructor =
      if (constructorSymbol.isMethod) constructorSymbol.asMethod
      else {
        val ctors = constructorSymbol.asTerm.alternatives
        ctors.map(_.asMethod).find(_.isPrimaryConstructor).get
      }

    ListMap[String, Type]() ++ defaultConstructor.paramLists.reduceLeft(_ ++ _).map {
      sym => sym.name.toString -> tpe.member(sym.name).asMethod.returnType
    }
  }


来源:https://stackoverflow.com/questions/16079113/scala-2-10-reflection-how-do-i-extract-the-field-values-from-a-case-class-i-e

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!