14

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?

EthanP
  • 1,663
  • 3
  • 22
  • 27
jarandaf
  • 4,297
  • 6
  • 38
  • 67
  • If I understand you correctly and you would only like to serialize `myMap`, why not call `Serialization.write(myMap)` directly? – edi Jan 08 '15 at 16:37
  • 1
    @user3567830 I want a JSON string representation of `myMap`, that's the purpose of using a JSON scala library such as `json4s` – jarandaf Jan 08 '15 at 18:44
  • 2
    Yes, `org.json4s.jackson.Serialization.write(myMap)` does exactly that. (I used the jackson version of json4s, but this should work for the native version as well). – edi Jan 08 '15 at 18:45
  • @user3567830 This are great news (missed the Serialization chapter when reading the docs, too much scrolling :D). Please feel free to post your answer, I will gladly accept it. Thank you! – jarandaf Jan 08 '15 at 19:04

2 Answers2

37

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)) 
edi
  • 3,112
  • 21
  • 16
  • 3
    Just for further reference, an implicit `Formats` instance is required, otherwise the following error shows up: `No org.json4s.Formats found. Try to bring an instance of org.json4s.Formats in scope or use the org.json4s.DefaultFormats.`. For instance, `implicit val formats = org.json4s.DefaultFormats` solves the problem. – jarandaf Jan 08 '15 at 19:25
-2

json4s has method for it.

pretty(render(yourMap))
Roman Kazanovskyi
  • 3,370
  • 1
  • 21
  • 22