-
Notifications
You must be signed in to change notification settings - Fork 0
JSON
Introduced with 0.0.8-SNAPSHOT, Salat's JSON support leverages json4s to cleanly move between JSON and your model objects.
Simplicity. Flexibility. Consistency.
- provide JSON serialization that is consistent with
DBObjectbehaviour while being customizable for JSON-specific concerns - avoid model contortions like
Optionparameters that contain boolean values, maps, or collections - avoid "double entry" annotations, where your model is annotated once for Salat and once for another JSON library
- JSON object <-> model object
- JSON array of objects <-> list of model objects
- default arguments
-
Salat annotations -
@Key,@Ignore,@Persist,@Salat - customizable date strategy
- customizable ObjectId strategy
Create some model objects in model.scala:
package model
import com.novus.salat.annotations._
import org.joda.time.DateTime
import org.bson.types.ObjectId
import com.novus.salat.annotations._
case class Amsterdam(@Key("_id") id: ObjectId,
a: String,
b: Int,
c: Double,
d: Boolean,
e: DateTime)
@Salat
trait Baltimore {
@Key("_id") def id: ObjectId // when you use @Key in a superclass, you don't have to repeat yourself!
def s: String
}
case class Casablanca(id: ObjectId, s: String) extends Baltimore
case class Denmark(id: ObjectId, s: String, d: Double) extends Baltimore
case class Edison(d: DateTime)Create a custom context in context.scala:
package myApp
import com.novus.salat.{TypeHintFrequency, StringTypeHintStrategy, Context}
import com.novus.salat.json.{StringDateStrategy, JSONConfig}
import org.joda.time.format.ISODateTimeFormat
import org.joda.time.DateTimeZone
package object context {
implicit val ctx = new Context {
val name = "json-test-context"
override val typeHintStrategy = StringTypeHintStrategy(when = TypeHintFrequency.WhenNecessary,
typeHint = "_t")
override val jsonConfig = JSONConfig(dateStrategy =
StringDateStrategy(dateFormatter = ISODateTimeFormat.dateTime.withZone("US/Eastern")))
}
}Use the following setup in sbt console:
scala> import com.novus.salat._
import com.novus.salat._
scala> import model._
import model._
scala> import myApp.context._
import myApp.context._
scala> import org.scala_tools.time.Imports._
import org.scala_tools.time.Imports._
scala> val id = new org.bson.types.ObjectId
id: org.bson.types.ObjectId = 4fdf3bc2c89cd58b22f27811
scala> val s = "Hello"
s: java.lang.String = Hello
scala> val i = 99 // problems but <-> JSON is no longer one
i: Int = 99
scala> val d = 3.14
d: Double = 3.14
scala> val b = false
b: Boolean = false
scala> val dt = new DateTime(2011, 12, 28, 14, 37, 56, 8, DateTimeZone.forID("US/Eastern"))
dt: org.joda.time.DateTime = 2011-12-28T14:37:56.008-05:00
scala> val a = Amsterdam(id = id, s = s, i = i, d = d, b = b, dt = dt)
a: model.Amsterdam = Amsterdam(4fdf3bc2c89cd58b22f27811,Hello,99,3.14,false,2011-12-28T14:37:56.008-05:00)
scala> val b = List(Casablanca(id = new ObjectId, s = "c"), Denmark(id = new ObjectId, s = "d", d = 1.618))
b: List[Product with model.Baltimore] = List(Casablanca(4fe5f9ef4cea1c9d3216fe5a,c), Denmark(4fe5f9ef4cea1c9d3216fe5b,d,1.618))scala> grater[Amsterdam].toJSON(a)
res0: org.json4s.JsonAST.JObject = JObject(List(JField(_id,JObject(List(JField($oid,JString(4fdf3bc2c89cd58b22f27811))))), JField(s,JString(Hello)), JField(i,JInt(99)), JField(d,JDouble(3.14)), JField(b,JBool(false)), JField(dt,JString(2011-12-28T19:37:56.008Z))))scala> grater[Baltimore].toJSONArray(b)
res1: org.json4s.JsonAST.JArray = JArray(List(JObject(List(JField(_t,JString(model.Casablanca)), JField(_id,JString(4fe5f9ef4cea1c9d3216fe5a)), JField(s,JString(c)))), JObject(List(JField(_t,JString(model.Denmark)), JField(_id,JString(4fe5f9ef4cea1c9d3216fe5b)), JField(s,JString(d)), JField(d,JDouble(1.618))))))scala> grater[Amsterdam].toPrettyJSON(a)
res1: String =
{
"_id":{
"$oid":"4fdf3bc2c89cd58b22f27811"
},
"s":"Hello",
"i":99,
"d":3.14,
"b":false,
"dt":"2011-12-28T19:37:56.008Z"
}
scala> grater[Baltimore].toPrettyJSONArray(b)
res3: String =
[{
"_t":"model.Casablanca",
"_id":"4fe5f9ef4cea1c9d3216fe5a",
"s":"c"
},{
"_t":"model.Denmark",
"_id":"4fe5f9ef4cea1c9d3216fe5b",
"s":"d",
"d":1.618
}]scala> grater[Amsterdam].toCompactJSON(a)
res3: String = {"_id":{"$oid":"4fdf3bc2c89cd58b22f27811"},"s":"Hello","i":99,"d":3.14,"b":false,"dt":"2011-12-28T19:37:56.008Z"}
scala> grater[Baltimore].toCompactJSONArray(b)
res2: String = [{"_t":"model.Casablanca","_id":"4fe5f9ef4cea1c9d3216fe5a","s":"c"},{"_t":"model.Denmark","_id":"4fe5f9ef4cea1c9d3216fe5b","s":"d","d":1.618}]Supports:
- from
JObjector string representing a JSON object to model object - from
JArrayor string representing an array of JSON objects to list of model objects
scala> val j = grater[Amsterdam].toCompactJSON(a)
j: String = {"_id":{"$oid":"4fdf3bc2c89cd58b22f27811"},"s":"Hello","i":99,"d":3.14,"b":false,"dt":"2011-12-28T14:37:56.008-05:00"}
scala> val a_* = grater[Amsterdam].fromJSON(j)
a_*: model.Amsterdam = Amsterdam(4fdf3bc2c89cd58b22f27811,Hello,99,3.14,false,2011-12-28T14:37:56.008-05:00)
scala> a_* == a
res0: Boolean = true
scala> val arr = grater[Baltimore].toJSONArray(b)
arr: org.json4s.JsonAST.JArray = JArray(List(JObject(List(JField(_t,JString(model.Casablanca)), JField(_id,JString(4fe5f9ef4cea1c9d3216fe5a)), JField(s,JString(c)))), JObject(List(JField(_t,JString(model.Denmark)), JField(_id,JString(4fe5f9ef4cea1c9d3216fe5b)), JField(s,JString(d)), JField(d,JDouble(1.618))))))
scala> val b_* = grater[Baltimore].fromJSONArray(arr)
b_*: List[model.Baltimore] = List(Casablanca(4fe5f9ef4cea1c9d3216fe5a,c), Denmark(4fe5f9ef4cea1c9d3216fe5b,d,1.618))
scala> b_* == b
res4: Boolean = trueJSON specific configuration is provided by com.novus.salat.json.JSONConfig.
Currently you can configure:
- type hinting
- date strategy
-
ObjectIdstrategy - ability to output null values
Import myApp.context._. Don't import com.novus.salat.global._.
package myApp
import com.novus.salat.{ TypeHintFrequency, StringTypeHintStrategy, Context }
import com.novus.salat.json._
import org.joda.time.format.ISODateTimeFormat
import org.joda.time.DateTimeZone
package object context {
implicit val ctx = new Context {
val name = "json-test-context"
override val typeHintStrategy = StringTypeHintStrategy(when = TypeHintFrequency.WhenNecessary,
typeHint = "_t")
override val jsonConfig = JSONConfig(
dateStrategy = StringDateStrategy(dateFormatter = ISODateTimeFormat.dateTime.withZone(DateTimeZone.forID("US/Eastern"))),
objectIdStrategy = StringObjectIdStrategy)
}
}One question: will you ever need to deserialize JSON output into model objects?
If the answer is yes, use the "when necessary" type hinting strategy with a short type hint key:
package myApp
import com.novus.salat.{TypeHintFrequency, StringTypeHintStrategy, Context}
package object when_necessary_context {
implicit val ctx = new Context {
val name = "json-context"
override val typeHintStrategy = StringTypeHintStrategy(when = TypeHintFrequency.WhenNecessary,
typeHint = "_t")
}
}package myApp
import com.novus.salat.{NeverTypeHint, Context}
package object never_typehint_context {
implicit val ctx = new Context {
val name = "json-context"
override val typeHintStrategy = NeverTypeHint
}
}Salat supplies the following options for handling ObjectId in JSON.
scala> val d = Denmark(id = new ObjectId("4fe5f9ef4cea1c9d3216fe5b"), s = "d", d = 1.618)
d: model.Denmark = Denmark(4fe5f9ef4cea1c9d3216fe5b,d,1.618)StrictJSONObjectIdStrategy serializes your ObjectId as a JSON object with key $oid
scala> grater[Denmark].toPrettyJSON(d)
res0: String =
{
"_t":"model.Denmark",
"_id":{
"$oid":"4fe5f9ef4cea1c9d3216fe5b"
},
"s":"d",
"d":1.618
}StringObjectIdStrategy serializes your ObjectId as a sring
scala> grater[Denmark].toPrettyJSON(d)
res5: String =
{
"_t":"model.Denmark",
"_id":"4fe5f9ef4cea1c9d3216fe5b",
"s":"d",
"d":1.618
}Extend JSONObjectIdStrategy and do whatever you like.
Time zone defaults to DateTimeZone.UTC. To use a different time zone, explicitly supply it: the examples show how to
use US/Eastern instead of UTC.
scala> val dt = new DateTime(2011, 12, 28, 14, 37, 56, 8, DateTimeZone.forID("US/Eastern"))
dt: org.joda.time.DateTime = 2011-12-28T14:37:56.008-05:00
scala> val e = Edison(d = dt)
e: model.Edison = Edison(2011-12-28T14:37:56.008-05:00)StringDateStrategy
- serializes dates as strings according to a custom format
- defaults to ISO8601 format with UTC time zone for serializing and deserializing dates
scala> grater[Edison].toPrettyJSON(e)
res0: String =
{
"d":"2011-12-28T14:37:56.008-05:00"
}TimestampDateStrategy
- serializes dates as a unix timestamp
- deserializes to
DateorDateTimeusing supplied time zone - defaults to UTC time zone when deserializing dates
scala> grater[Edison].toPrettyJSON(e)
res0: String =
{
"d":1325101076008
}StrictJSONDateStrategy
- output dates as an object
$dateas the key and a timestamp as the value - defaults to UTC time zone when deserializing dates
scala> grater[Edison].toPrettyJSON(e)
res0: String =
{
"d":{
"$date":1325101076008
}
}Implement JSONDateStrategy to produce a custom date serialization.