summaryrefslogtreecommitdiff
path: root/README.markdown
diff options
context:
space:
mode:
authorMathias <mathias@spray.cc>2012-02-01 15:17:39 +0100
committerMathias <mathias@spray.cc>2012-02-01 15:17:39 +0100
commit86a975a4857bf6ee207e30fe4a7fc427345fb08b (patch)
treedbb4631ee197afc3f64edcc329c1595221010c76 /README.markdown
parent23ba08be46c3d31b26528cb54e28f3516307484f (diff)
downloadspray-json-86a975a4857bf6ee207e30fe4a7fc427345fb08b.tar.gz
spray-json-86a975a4857bf6ee207e30fe4a7fc427345fb08b.tar.bz2
spray-json-86a975a4857bf6ee207e30fe4a7fc427345fb08b.zip
Update README
Diffstat (limited to 'README.markdown')
-rw-r--r--README.markdown89
1 files changed, 50 insertions, 39 deletions
diff --git a/README.markdown b/README.markdown
index 3ff1d02..cca4603 100644
--- a/README.markdown
+++ b/README.markdown
@@ -10,15 +10,16 @@ It sports the following features:
### Installation
-_spray-json_ is available from the [scala-tools.org] repositories.
-The latest release is `1.0.1` and is built against Scala 2.9.1.
+_spray-json_ is available from the [repo.spray.cc] repositories.
+The latest release is `1.1.0` and is built against Scala 2.9.1.
-If you use SBT (0.7.x) you can include _spray-json_ in your project with
+If you use SBT you can include _spray-json_ in your project with
- val sprayJson = "cc.spray.json" %% "spray-json" % "1.0.1" % "compile" withSources()
+ "cc.spray" %% "spray-json" % "1.1.0"
_spray-json_ has only one dependency: the parsing library [parboiled][]
-(which is also a dependency of _spray-server_ and _spray-client_, so if you use _spray-json_ with either of them you are not incurring any additional dependency).
+(which is also a dependency of _spray-server_ and _spray-client_, so if you use _spray-json_ with either of them you
+are not incurring any additional dependency).
### Usage
@@ -54,16 +55,24 @@ The way you normally do this is via a "JsonProtocol".
### JsonProtocol
-_spray-json_ uses [SJSON]s Scala-idiomatic type-class-based approach to connect an existing type `T` with the logic how to (de)serialize its instances to and from JSON. (In fact _spray-json_ even reuses some of [SJSON]s code, see the 'Credits' section below).
+_spray-json_ uses [SJSON]s Scala-idiomatic type-class-based approach to connect an existing type `T` with the logic how
+to (de)serialize its instances to and from JSON. (In fact _spray-json_ even reuses some of [SJSON]s code, see the
+'Credits' section below).
This approach has the advantage of not requiring any change (or even access) to `T`s source code. All (de)serialization
-logic is attached 'from the outside'. There is no reflection involved, so the resulting conversions are fast. Scalas excellent type inference reduces verbosity and boilerplate to a minimum, while the Scala compiler will make sure at compile time that you provided all required (de)serialization logic.
+logic is attached 'from the outside'. There is no reflection involved, so the resulting conversions are fast. Scalas
+excellent type inference reduces verbosity and boilerplate to a minimum, while the Scala compiler will make sure at
+compile time that you provided all required (de)serialization logic.
-In _spray-jsons_ terminology a 'JsonProtocol' is nothing but a bunch of implicit values of type `JsonFormat[T]`, whereby each `JsonFormat[T]` contains the logic of how to convert instance of `T` to and from JSON. All `JsonFormat[T]`s of a protocol need to be "mece" (mutually exclusive, collectively exhaustive), i.e. they are not allowed to overlap and together need to span all types required by the application.
+In _spray-jsons_ terminology a 'JsonProtocol' is nothing but a bunch of implicit values of type `JsonFormat[T]`, whereby
+each `JsonFormat[T]` contains the logic of how to convert instance of `T` to and from JSON. All `JsonFormat[T]`s of a
+protocol need to be "mece" (mutually exclusive, collectively exhaustive), i.e. they are not allowed to overlap and
+together need to span all types required by the application.
This may sound more complicated than it is.
-_spray-json_ comes with a `DefaultJsonProtocol`, which already covers all of Scalas value types as well as the most important reference and collection types. As long as your code uses nothing more than these you only need the `DefaultJsonProtocol`.
-Here are the types already taken care of by the `DefaultJsonProtocol`:
+_spray-json_ comes with a `DefaultJsonProtocol`, which already covers all of Scalas value types as well as the most
+important reference and collection types. As long as your code uses nothing more than these you only need the
+`DefaultJsonProtocol`. Here are the types already taken care of by the `DefaultJsonProtocol`:
* Byte, Short, Int, Long, Float, Double, Char, Unit, Boolean
* String, Symbol
@@ -74,7 +83,8 @@ Here are the types already taken care of by the `DefaultJsonProtocol`:
* collection.{Iterable, Seq, IndexedSeq, LinearSeq, Set}
* JsValue
-In most cases however you'll also want to convert types not covered by the `DefaultJsonProtocol`. In these cases you need to provide `JsonFormat[T]`s for your custom types. This is not hard at all.
+In most cases however you'll also want to convert types not covered by the `DefaultJsonProtocol`. In these cases you
+need to provide `JsonFormat[T]`s for your custom types. This is not hard at all.
### Providing JsonFormats for Case Classes
@@ -84,7 +94,7 @@ If your custom type `T` is a case class then augmenting the `DefaultJsonProtocol
case class Color(name: String, red: Int, green: Int, blue: Int)
object MyJsonProtocol extends DefaultJsonProtocol {
- implicit val colorFormat = jsonFormat(Color, "name", "red", "green", "blue")
+ implicit val colorFormat = jsonFormat4(Color)
}
import MyJsonProtocol._
@@ -92,26 +102,32 @@ If your custom type `T` is a case class then augmenting the `DefaultJsonProtocol
val json = Color("CadetBlue", 95, 158, 160).toJson
val color = json.convertTo[Color]
-The `jsonFormat` method reduces the boilerplate to a minimum, just pass it the companion object of your case class as
-well as the field names (in order) and it will return a ready-to-use `JsonFormat` for your type.
-There is one quirk though: If you explicitly declare the companion object for your case class the notation above will
+The `jsonFormatX` methods reduce the boilerplate to a minimum, just pass the right one the companion object of your
+case class and it will return a ready-to-use `JsonFormat` for your type (the right one is the one matching the number
+of arguments to your case class constructor, e.g. if your case class has 13 fields you need to use the `jsonFormat13`
+method). The `jsonFormatX` methods try to extract the field names of your case class before calling the more general
+`jsonFormat` overloads, which let you specify the field name manually. So, if spray-json has trouble determining the
+field names or if your JSON objects use member names that differ from the case class fields you can also use
+`jsonFormat` directly.
+
+There is one additional quirk: If you explicitly declare the companion object for your case class the notation above will
stop working. You'll have to explicitly refer to the companion objects `apply` method to fix this:
case class Color(name: String, red: Int, green: Int, blue: Int)
object Color
object MyJsonProtocol extends DefaultJsonProtocol {
- implicit val colorFormat = jsonFormat(Color.apply, "name", "red", "green", "blue")
+ implicit val colorFormat = jsonFormat4(Color.apply)
}
-If your case class is generic in that it takes type parameters itself the `jsonFormat` method can also help you.
+If your case class is generic in that it takes type parameters itself the `jsonFormat` methods can also help you.
However, there is a little more boilerplate required as you need to add context bounds for all type parameters
and explicitly refer to the case classes `apply` method as in this example:
case class NamedList[A](name: String, items: List[A])
object MyJsonProtocol extends DefaultJsonProtocol {
- implicit def namedListFormat[A :JsonFormat] = jsonFormat(NamedList.apply[A], "name", "items")
+ implicit def namedListFormat[A :JsonFormat] = jsonFormat2(NamedList.apply[A])
}
@@ -124,13 +140,12 @@ Here is one way to do it:
object MyJsonProtocol extends DefaultJsonProtocol {
implicit object ColorJsonFormat extends JsonFormat[Color] {
- def write(c: Color) = {
+ def write(c: Color) =
JsArray(JsString(c.name), JsNumber(c.red), JsNumber(c.green), JsNumber(c.blue))
- }
+
def read(value: JsValue) = value match {
- case JsArray(JsString(name) :: JsNumber(red) :: JsNumber(green) :: JsNumber(blue) :: Nil) => {
+ case JsArray(JsString(name) :: JsNumber(red) :: JsNumber(green) :: JsNumber(blue) :: Nil) =>
new Color(name, red.toInt, green.toInt, blue.toInt)
- }
case _ => deserializationError("Color expected")
}
}
@@ -146,30 +161,26 @@ You need to know that the color components are ordered "red, green, blue".
Another way would be to serialize `Color`s as JSON objects:
- object MyJsonProtocol extends DefaultJsonProtocol {
+ object MyJsonProtocol extends DefaultJsonProtocol {
implicit object ColorJsonFormat extends JsonFormat[Color] {
def write(c: Color) = JsObject(
- JsField("name", c.name),
- JsField("red", c.red),
- JsField("green", c.green),
- JsField("blue", c.blue)
+ "name" -> JsString(c.name),
+ "red" -> JsNumber(c.red),
+ "green" -> JsNumber(c.green),
+ "blue" -> JsNumber(c.blue)
)
- def read(value: JsValue) = value match {
- case JsObject(
- JsField("name", JsString(name)),
- JsField("red", JsNumber(red)),
- JsField("green", JsNumber(green)),
- JsField("blue", JsNumber(blue))
- ) => {
- new Color(name.value, red.value.toInt, green.value.toInt, blue.value.toInt)
+ def read(value: JsValue) = {
+ value.asJsObject.getFields("name", "red", "green", "blue") match {
+ case Seq(JsString(name), JsNumber(red), JsNumber(green), JsNumber(blue)) =>
+ new Color(name, red.toInt, green.toInt, blue.toInt)
+ case _ => throw new DeserializationException("Color expected")
}
- case _ => deserializationError("Color expected")
}
}
}
-This is a bit more verbose in its definition and the resulting JSON but transports the field semantics over to the JSON side.
-Note that this is the approach _spray-json_ uses for case classes.
+This is a bit more verbose in its definition and the resulting JSON but transports the field semantics over to the
+JSON side. Note that this is the approach _spray-json_ uses for case classes.
### JsonFormats for recursive Types
@@ -214,7 +225,7 @@ _spray-json_ project under the project’s open source license.
[JSON]: http://json.org
[parboiled]: http://parboiled.org
- [scala-tools.org]: http://scala-tools.org
+ [repo.spray.cc]: http://repo.spray.cc
[SJSON]: https://github.com/debasishg/sjson
[Databinder-Dispatch]: https://github.com/n8han/Databinder-Dispatch
[APL 2.0]: http://www.apache.org/licenses/LICENSE-2.0