zipping case classes in scala
Let’s say we have a Scala method that takes an input param of Map[String, Any], where String is a DB column name and Any is the value.
However the data we need to insert into the DB is in the format of a Scala case class.
How do we convert the case class to a Map for DB insertion?
First let’s compare the input and output:
Existing data structure:
case class LogMessage(date: String, event: String, elapsedTimeMs: Int)What our DB service requires:
val dbMsg = Map("date" -> "June 3", "event" -> "User Logged In", "elapsedTimeMs" -> 13)So let’s do the conversion.
Since Scala case classes extend the Product trait, our method signature will accept a Product, and depend on its productIterator implementation.
private def caseClassToMap(obj: Product): Map[String, Any] = {
}To obtain the “keys” for our map, we will use some standard Java reflection methods:
private def caseClassToMap(obj: Product): Map[String, Any] = {
  val keys = obj.getClass.getDeclaredFields.map(_.getName).toList
}To obtain the “values” for our map, we will use the productIterator method that our class class implements based on it extending the Product trait:
private def caseClassToMap(obj: Product): Map[String, Any] = {
  val keys = obj.getClass.getDeclaredFields.map(_.getName).toList
  val values = obj.productIterator.toList
}Now we have extracted our values, we need to zip them together into a map.
private def caseClassToMap(obj: Product): Map[String, Any] = {
  val keys = obj.getClass.getDeclaredFields.map(_.getName).toList
  val values = obj.productIterator.toList
  keys.zip(values).toMap
}Now we can perform the conversion.
case class LogMessage(date: String, event: String, elapsedTimeMs: Int)
val msg = LogMessage("June 3", "User Logged In", 13)
caseClassToMap(msg)
//=> Map[String,Any] = Map(date -> June 3, event -> User Logged In, elapsedTimeMs -> 13)