I\'ve not had much joy with reflection, this answer using shapeless works for some cases (but seems to have many edge cases) Shapeless code to convert Map[String, Any] to ca
I've found a reasonably neat way to do it using Spray Json
First we define a way to get to a JsObject
from a Map[String, Any]
def mapToJsObject(map: Map[String, Any]): JsObject =
JsObject(fields = map.mapValues(anyToJsValue))
def anyToJsValue(any: Any): JsValue = any match {
case n: Int => JsNumber(n)
case n: Long => JsNumber(n)
case n: Double => JsNumber(n)
case s: String => JsString(s)
case true => JsTrue
case false => JsFalse
case null | None => JsNull
case list: List[_] => JsArray(list.map(anyToJsValue).toVector)
case Some(any) => anyToJsValue(any)
case map: Map[String, Any] => mapToJsObject(map)
}
Then we can just use convertTo
provided we have the implicit JsonFormat
in scope
case class Address(street: String, zip: Int)
case class Person(name: String, address: Address)
implicit val addressFormat = jsonFormat2(Address.apply)
implicit val personFormat = jsonFormat2(Person.apply)
"Convert Person example map to Person JsObject" in {
JsonUtils.mapToJsObject(
Map(
"name" -> "Tom",
"address" -> Map("street" -> "Jefferson st", "zip" -> 10000)
)
).convertTo[Person] must_=== Person("Tom", Address("Jefferson st", 10000))
}
Spray json only has out of box jsonFormat up to 22 fields!
Can not handle any custom types, e.g. java.sql.Timestamp
, since this isn't a JSON type.