Some time ago I wrote a post on relational database access in Scala since I was looking for a library and there were many of them available, making it hard to make a choice. It turns out that the situation is similar if not worse when it comes to JSON libraries in Scala.
There are just plenty of them. You have no idea. (me neither until I wrote this post)
The following is an attempt to provide a quick overview at how a subset of the libraries I found does a few of the most common things one would likely need to do in regard to JSON:
parsing it from a raw string
browsing the AST
building an AST
mapping to a case class
There are of course plenty more valid use-cases but this post is not going to cover those.
Let’s get started!
Scala JSON libraries
play-json
The Play Framework comes with a JSON library that covers most of the common use-cases one would encounter when building web applications:
This is quite useful, it removes the boilerplate formats hanging around
json4s
json4s is a bit like slf4j in the sense that it tries to unite all kind of rogue libraries serving the same purpose by providing a common interface. But not every library uses it, which means that chances are high that your project will contain json4s in addition to another (few) Scala JSON libraries. Hopefully it will one day succeed with its slogan “One AST to rule them all”.
json4s has its roots in lift-json so this will look familiar:
The sphere-json library focuses on providing an easy way to get de/serializers for entire families of case classes. This is really useful when working with any kind of protocol-related system. I am using it in a CQRS system where commands and events are travelling back and forth between the server and a Javascript UI. Instead of having to define a codec for each one of my case classes, I simply have them extend a common abstract class and let the library take care of the rest. Watch for yourselves:
rapture’sjson library is the ultimate Scala JSON library. It doesn’t really do anything with JSON itself, instead, it abstracts over the following JSON libraries (which it calls backends):
Robert J. Macomber built the rojoma-json library which I only discovered now and am too tired to cover (sorry)
Great, now which one to pick?
All of them
Honestly I don’t have any good advice here. These days I am sticking to play-json and sphere-json, but that’s for no particular reason other than these libraries being there and doing what I need to do (parse and write JSON, traverse and some rare times transform the AST, bind to case classes, make it possible to support custom Java types). If play-json had support for hierarchies out of the box I would probably not have even looked for anything else.
Because for all the joy there seems to be in implementing JSON libraries in Scala, one thing has to be said: JSON de/serialization is boring. It’s this annoying thing that you have to do in order to get your application to talk to another computerized system, period.
I have never met a developer who told me how much pleasure they derived from turning classes into JSON strings and back. That’s just not a thing.
I have, however, met more than one developer that has run into trouble getting library X to cover one of the simple use-cases outlined above. Believe me, there is nothing more frustrating than having to spend time on the annoying task of setting up JSON de/serialization in order to do the boring thing of tossing strings back and forth the network. That’s time you will never get back.
Two years ago I started from your quick tour for selection of JSON parser and, sure, never thought that it will end up by writing of own one: https://github.com/plokhotnyuk/jsoniter-scala
How it differs from others?
It is developed for requirements of real-time bidding in ad-tech and goals are simple:
1) do parsing & serialization of JSON directly from UTF-8 bytes to your case classes & Scala collections and back but do it crazily fast w/o reflection, intermediate syntax tree, strings or events, w/ minimum allocations & copying
2) do not replace illegally encoded characters of string values by placeholder characters and do not allow broken surrogate pairs of characters to be parsed or serialized
One extra feature where play-json shines is validation and pointing to the location where things went wrong. I wonder if the other candidates have a similar feature.
L
Leo Heinman
0 points
8 years ago
The JSON utility in Scala standard library is deprecated.
B
Barbaros
0 points
9 years ago
Thanks for the great article.
Actually I am having a little problem with play-json 2.4.8 and spark 1.6.1. Because of Spark 1.6.1 uses jackson-databind 2.4.4 and play-json 2.4.8 uses jackson-databind 2.5.4.
I have added this line to build.sbt to force which version to use.
It works on my local machine. But when I submit it to EMR runnin Spark 1.6.1, an error occured like below:
java.lang.NoClassDefFoundError: play/api/libs/json/JsValue
Do you have any idea about what's happening?
A
Andriy Plokhotnyuk
0 points
8 years ago
Great work, Manuel!
Two years ago I started from your quick tour for selection of JSON parser and, sure, never thought that it will end up by writing of own one: https://github.com/plokhotnyuk/jsoniter-scala
How it differs from others?
It is developed for requirements of real-time bidding in ad-tech and goals was simple:
1) do parsing & serialization of JSON directly from UTF-8 bytes to your case classes & Scala collections and back but do it crazily fast w/o reflection, intermediate syntax tree, strings or events, w/ minimum allocations & copying
2) do not replace illegally encoded characters of string values by placeholder characters and do not allow broken surrogate pairs of characters to be parsed or serialized
Nice analysis. One use case I am missing: Partial JSON objects. Often for updates a client only sends the changed fields of a JSON structure back. Some libraries support this use case and can transform such a response into a function that updates exactly the given fields in a matching case class. This is sometimes goes under the name incomplete decoders.
Great overview!
A correction - spray-json does support AST navigation (though not in the most pleasant way). Example:
import spray.json._ import DefaultJsonProtocol._
case class MyClass(hello: String, age: Int)
implicit myFormat = jsonFormat2(MyClass)
val ast = """{"hello":"world","age":42}""".parseJson
ast.asJsObject.getFields("hello").head.toString
Constructing an AST:
JsObject(("hello" -> JsString("world")), ("age" -> JsNumber(42)))
Thank you so much for this list and the examples. Especially considering the current discussion about adding an AST to the scala stdlib.
One other important note regarding spray-json - I believie it is the only library listed which preserves field order in objects.
check out our new lib, also preserves order!
https://github.com/MediaMath/scala-json
Nice analysis - thanks! I wanted to point out that in Argonaut you should also check out CodecJson.derive, eg
implicit val codec = CodecJson.derive[CaseClass]
Great article! I've got a new one for your list:
https://github.com/MediaMath/scala-json
Painfully tried to match the feature set of existing scala and scala-js JSON libraries, and we've done it and more!
Cross compiles for 2.10-2.12 X scala/scala-js-0.6
Nice set of examples. You might want to also check out my presentation comparing performance of the various Scala Json Libraries.
http://www.slideshare.net/nestorhp/scala-json-features-and-performance
Great work, Manuel!
Two years ago I started from your quick tour for selection of JSON parser and, sure, never thought that it will end up by writing of own one: https://github.com/plokhotnyuk/jsoniter-scala
How it differs from others?
It is developed for requirements of real-time bidding in ad-tech and goals are simple:
1) do parsing & serialization of JSON directly from UTF-8 bytes to your case classes & Scala collections and back but do it crazily fast w/o reflection, intermediate syntax tree, strings or events, w/ minimum allocations & copying
2) do not replace illegally encoded characters of string values by placeholder characters and do not allow broken surrogate pairs of characters to be parsed or serialized
Very nice review
One extra feature where play-json shines is validation and pointing to the location where things went wrong. I wonder if the other candidates have a similar feature.
The JSON utility in Scala standard library is deprecated.
Thanks for the great article. Actually I am having a little problem with play-json 2.4.8 and spark 1.6.1. Because of Spark 1.6.1 uses jackson-databind 2.4.4 and play-json 2.4.8 uses jackson-databind 2.5.4.
I have added this line to build.sbt to force which version to use.
dependencyOverrides ++= Set( "com.fasterxml.jackson.core" % "jackson-databind" % "2.4.4" )
It works on my local machine. But when I submit it to EMR runnin Spark 1.6.1, an error occured like below: java.lang.NoClassDefFoundError: play/api/libs/json/JsValue
Do you have any idea about what's happening?
Great work, Manuel!
Two years ago I started from your quick tour for selection of JSON parser and, sure, never thought that it will end up by writing of own one: https://github.com/plokhotnyuk/jsoniter-scala
How it differs from others?
It is developed for requirements of real-time bidding in ad-tech and goals was simple:
1) do parsing & serialization of JSON directly from UTF-8 bytes to your case classes & Scala collections and back but do it crazily fast w/o reflection, intermediate syntax tree, strings or events, w/ minimum allocations & copying
2) do not replace illegally encoded characters of string values by placeholder characters and do not allow broken surrogate pairs of characters to be parsed or serialized
FYI: scala.util.parsing.json is now deprecated as of scala 2.12.3: https://github.com/scala/scala-parser-combinators/issues/99
Nice analysis. One use case I am missing: Partial JSON objects. Often for updates a client only sends the changed fields of a JSON structure back. Some libraries support this use case and can transform such a response into a function that updates exactly the given fields in a matching case class. This is sometimes goes under the name incomplete decoders.
Nice post, wondered what your thoughts were on my post regarding xml processing in scala, the post is a bit old now. http://joncook.github.io/blog/2013/11/03/xml-processing-with-scala/ and on githib https://github.com/JonCook/scala-xml-parsing-example