Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

case class from Map

I'm trying to implement (de)serialization from Scala case classes to Maps (field_name -> field_value). The problem is I don't know how to create a function, that would take a case class type and a map, instantiate, populate and return it. I've seen this done in some JSON libraries, but I don't get the code.

like image 780
Dark Avatar asked Jan 13 '13 15:01

Dark


1 Answers

Doing this for a particular case class is trivial:

scala> :paste
// Entering paste mode (ctrl-D to finish)

case class Foo(x: Int, y: Double, z: String) {
  def toMap = Map('x -> x, 'y -> y, 'z -> z)
}
object Foo {
  def apply(vals: Map[Symbol, Any]): Foo = Foo(vals('x).asInstanceOf[Int], vals('y).asInstanceOf[Double], vals('z).asInstanceOf[String])
}

// Exiting paste mode, now interpreting.

defined class Foo
defined module Foo

scala> Foo(Map('x -> 1, 'y -> 2.0, 'z -> "wibble"))
res0: Foo = Foo(1,2.0,wibble)

scala> res0.toMap
res1: scala.collection.immutable.Map[Symbol,Any] = Map('x -> 1, 'y -> 2.0, 'z -> wibble)

But I'm guessing that you want to create something that works for any case class, where you don't necessarily know what the names of the values are?

In which case, you're going to have to take a look at reflection (added in Scala 2.10.0):

http://docs.scala-lang.org/overviews/reflection/overview.html

You can use reflection to iterate over the members of a class, find out what their names are and then create your map. For example:

scala> import reflect.runtime.universe._
import reflect.runtime.universe._

scala> typeOf[Foo].members filter { m => m.isMethod && m.asMethod.isStable }
res2: Iterable[reflect.runtime.universe.Symbol] = SynchronizedOps(value z, value y, value x)
like image 51
Paul Butcher Avatar answered Oct 11 '22 12:10

Paul Butcher