Case class to map in Scala

This should work:

def getCCParams(cc: AnyRef) =
  cc.getClass.getDeclaredFields.foldLeft(Map.empty[String, Any]) { (a, f) =>
    f.setAccessible(true)
    a + (f.getName -> f.get(cc))
  }

Because case classes extend Product one can simply use .productIterator to get field values:

def getCCParams(cc: Product) = cc.getClass.getDeclaredFields.map( _.getName ) // all field names
                .zip( cc.productIterator.to ).toMap // zipped with all values

Or alternatively:

def getCCParams(cc: Product) = {          
      val values = cc.productIterator
      cc.getClass.getDeclaredFields.map( _.getName -> values.next ).toMap
}

One advantage of Product is that you don't need to call setAccessible on the field to read its value. Another is that productIterator doesn't use reflection.

Note that this example works with simple case classes that don't extend other classes and don't declare fields outside the constructor.


Starting Scala 2.13, case classes (as implementations of Product) are provided with a productElementNames method which returns an iterator over their field's names.

By zipping field names with field values obtained with productIterator we can generically obtain the associated Map:

// case class MyClass(param1: String, param2: String)
// val x = MyClass("hello", "world")
(x.productElementNames zip x.productIterator).toMap
// Map[String,Any] = Map("param1" -> "hello", "param2" -> "world")

If anybody looks for a recursive version, here is the modification of @Andrejs's solution:

def getCCParams(cc: Product): Map[String, Any] = {
  val values = cc.productIterator
  cc.getClass.getDeclaredFields.map {
    _.getName -> (values.next() match {
      case p: Product if p.productArity > 0 => getCCParams(p)
      case x => x
    })
  }.toMap
}

It also expands the nested case-classes into maps at any level of nesting.