Scala 2.10 reflection, how do I extract the field values from a case class, i.e. field list from case class
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
}
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
}
}