jarandaf jarandaf - 2 months ago 29
Scala Question

Map[String,Any] to compact json string using json4s

I am currently extracting some metrics from different data sources and storing them in a map of type

Map[String,Any]
where the key corresponds to the metric name and the value corresponds to the metric value. I need this to be more or less generic, which means that values types can be primitive types or lists of primitive types.

I would like to serialize this map to a JSON-formatted string and for that I am using
json4s
library. The thing is that it does not seem possible and I don't see a possible solution for that. I would expect something like the following to work out of the box :)

val myMap: Map[String,Any] = ... // extract metrics
val json = myMap.reduceLeft(_ ~ _) // create JSON of metrics


Navigating through source code I've seen
json4s
provides implicit conversions in order to transform primitive types to
JValue
's and also to convert
Traversable[A]/Map[String,A]/Option[A]
to
JValue
's (under the restriction of being available an implicit conversion from
A
to
JValue
, which I understand it actually means
A
is a primitive type). The
~
operator offers a nice way of constructing
JObject
's out of
JField
's, which is just a type alias for
(String, JValue)
.

In this case, map values type is
Any
, so implicit conversions don't take place and hence the compiler throws the following error:

value ~ is not a member of (String, Any)
[error] val json = r.reduceLeft(_ ~ _)


Is there a solution for what I want to accomplish?

edi edi
Answer

Since you are actually only looking for the JSON string representation of myMap, you can use the Serialization object directly. Here is a small example (if using the native version of json4s change the import to org.json4s.native.Serialization):

EDIT: added formats implicit

 import org.json4s.jackson.Serialization

 implicit val formats = org.json4s.DefaultFormats

 val m: Map[String, Any] = Map(
   "name "-> "joe",
   "children" -> List(
     Map("name" -> "Mary", "age" -> 5),
     Map("name" -> "Mazy", "age" -> 3)
   )
 )
 // prints {"name ":"joe","children":[{"name":"Mary","age":5},{"name":"Mazy","age":3}]}
 println(Serialization.write(m))