spray-json provides an easy way to work with JSON. Using implicit formats, everything happens "behind the scenes":
To manage spray-json
with SBT managed library dependencies:
libraryDependencies += "io.spray" %% "spray-json" % "1.3.2"
Note that the last parameter, the version number (1.3.2
), may be different in different projects.
The spray-json
library is hosted at repo.spray.io.
import spray.json._
import DefaultJsonProtocol._
The default JSON protocol DefaultJsonProtocol
contains formats for all basic types. To provide JSON functionality for custom types, either use convenience builders for formats or write formats explicitly.
// generates an intermediate JSON representation (abstract syntax tree)
val res = """{ "foo": "bar" }""".parseJson // JsValue = {"foo":"bar"}
res.convertTo[Map[String, String]] // Map(foo -> bar)
val values = List("a", "b", "c")
values.toJson.prettyPrint // ["a", "b", "c"]
DSL is not supported.
The following example shows how to serialize a case class object into the JSON format.
case class Address(street: String, city: String)
case class Person(name: String, address: Address)
// create the formats and provide them implicitly
implicit val addressFormat = jsonFormat2(Address)
implicit val personFormat = jsonFormat2(Person)
// serialize a Person
Person("Fred", Address("Awesome Street 9", "SuperCity"))
val fredJsonString = fred.toJson.prettyPrint
This results in the following JSON:
{
"name": "Fred",
"address": {
"street": "Awesome Street 9",
"city": "SuperCity"
}
}
That JSON can, in turn, be deserialized back into an object:
val personRead = fredJsonString.parseJson.convertTo[Person]
//Person(Fred,Address(Awesome Street 9,SuperCity))
Write a custom JsonFormat
if a special serialization of a type is required. For example, if the field names are different in Scala than in JSON. Or, if different concrete types are instantiated based on the input.
implicit object BetterPersonFormat extends JsonFormat[Person] {
// deserialization code
override def read(json: JsValue): Person = {
val fields = json.asJsObject("Person object expected").fields
Person(
name = fields("name").convertTo[String],
address = fields("home").convertTo[Address]
)
}
// serialization code
override def write(person: Person): JsValue = JsObject(
"name" -> person.name.toJson,
"home" -> person.address.toJson
)
}