In scala, how to turn object's values into Map[String, String]?

Yes it's possible. Since Scala 2.10 you can use reflection.

Assuming you have:

val test = Test(23423, "sdlkfjlsdk")

The following will get you what you want:

import reflect.runtime.universe._
import reflect.runtime.currentMirror

val r = currentMirror.reflect(test)
r.symbol.typeSignature.members.toStream
  .collect{case s : TermSymbol if !s.isMethod => r.reflectField(s)}
  .map(r => r.symbol.name.toString.trim -> r.get.toString)
  .toMap

To simply iterate over field values of case class use .productIterator on its instance.


The topic you are dealing with is becoming incredibly recurring on StackOverFlow and the problem is not trivial if you want to have a typesafe implementation.

One way to solve the problem is using reflection (as suggested) but I personally prefer using the type system and implicits.

There is a well-known library, developed by an extremely smart guy, who let you perform advanced operations such as turn any case class into a typesafe heterogeneous list, or create heteregeneous maps, which can be used to implement "extensible records". The library is called Shapeless, and here one example:

object RecordExamples extends App {
  import shapeless._
  import HList._
  import Record._

  object author  extends Field[String]  { override def toString = "Author" }
  object title   extends Field[String]  { override def toString = "Title" }
  object id      extends Field[Int]     { override def toString = "ID" }
  object price   extends Field[Double]  { override def toString = "Price" }
  object inPrint extends Field[Boolean] { override def toString = "In print" }

  def printBook[B <: HList](b : B)(implicit tl : ToList[B, (Field[_], Any)]) = {
    b.toList foreach { case (field, value) => println(field+": "+value) }
    println
  }

  val book =
    (author -> "Benjamin Pierce") ::
    (title  -> "Types and Programming Languages") ::
    (id     ->  262162091) ::
    (price  ->  44.11) ::
    HNil

  printBook(book)

  // Read price field
  val currentPrice = book.get(price)  // Static type is Double
  println("Current price is "+currentPrice)
  println

  // Update price field, relying on static type of currentPrice
  val updated = book + (price -> (currentPrice+2.0))
  printBook(updated)

  // Add a new field
  val extended = updated + (inPrint -> true)
  printBook(extended)

  // Remove a field
  val noId = extended - id 
  printBook(noId)
}

Book behaves like a typesafe map which can indexed using objects as keys. If you are interested in knowing more, a good entry point might be this post:

Are HLists nothing more than a convoluted way of writing tuples?

Tags:

Scala