-
Notifications
You must be signed in to change notification settings - Fork 31
Examples of Type Class based JSON serialization
Here are some examples that will help in understanding how the type class based serialization occurs in sjson :-
Here's a sample session in the REPL that illustrates how you serialize and de-serialize:
scala> case class Name(name: String)
defined class Name
scala> import sjson.json._
import sjson.json._
scala> import DefaultProtocol._
import DefaultProtocol._
scala> implicit val NameFormat: Format[Name] = wrap[Name, String]("name")(_.name, Name)
NameFormat: sjson.json.Format[Name] = sjson.json.Generic$$anon$2@1eed0fb
scala> val n = Name("debasish ghosh")
n: Name = Name(debasish ghosh)
scala> import JsonSerialization._
import JsonSerialization._
scala> val js = tojson(n)
js: dispatch.json.JsValue = {"name" : "debasish ghosh"}
scala> dispatch.json.JsValue.toJson(js)
res0: String = {"name" : "debasish ghosh"}
scala> fromjson[Name](js)
res1: Name = Name(debasish ghosh)
scala> res1 == n
res2: Boolean = true
Note in the above example, wrap
is the API that provides the type class implementation methods reads
and writes
. But all that's taken care of by the magic of implicits.
Here's the session in REPL:
scala> case class Shop(store: String, item: String, price: Int)
defined class Shop
scala> implicit val ShopFormat: Format[Shop] = asProduct3("store", "item", "price")(Shop)(Shop.unapply(_).get)
ShopFormat: sjson.json.Format[Shop] = sjson.json.Generic$$anon$4@42a751
scala> val shop = Shop("Shoppers Stop", "dress material", 1000)
shop: Shop = Shop(Shoppers Stop,dress material,1000)
scala> tojson(shop)
res3: dispatch.json.JsValue = {"store" : "Shoppers Stop", "item" : "dress material", "price" : 1000}
scala> dispatch.json.JsValue.toJson(res3)
res5: String = {"store" : "Shoppers Stop", "item" : "dress material", "price" : 1000}
scala> fromjson[Shop](res3)
res6: Shop = Shop(Shoppers Stop,dress material,1000)
scala> res6 == shop
res7: Boolean = true
In Scala, a Product
of 3 elements having types A
, B
and C
is a class whose instances are all possible elements of the cartesian product of A
, B
and C
. In the above example Shop
is a Product3
and the method asProduct3
supplies the type class implementation methods for it.
Here's the sample REPL session:
scala> case class Address(street: String, city: String, zip: String)
defined class Address
scala> implicit val AddressFormat: Format[Address] =
| asProduct3("street", "city", "zip")(Address)(Address.unapply(_).get)
AddressFormat: sjson.json.Format[Address] = sjson.json.Generic$$anon$4@c00e55
scala> case class Contact(name: String, addresses: List[Address])
defined class Contact
scala> implicit val ContactFormat: Format[Contact] =
| asProduct2("name", "addresses")(Contact)(Contact.unapply(_).get)
ContactFormat: sjson.json.Format[Contact] = sjson.json.Generic$$anon$3@f61f70
scala> val contact = Contact("Debasish Ghosh",
| List(Address("monroe st", "denver", "80231"), Address("pine drive", "santa clara", "95054")))
contact: Contact = Contact(Debasish Ghosh,List(Address(monroe st,denver,80231), Address(pine drive,santa clara,95054)))
scala> tojson(contact)
res8: dispatch.json.JsValue = {"name" : "Debasish Ghosh", "addresses" : [{"street" : "monroe st", "city" : "denver", "zip" : "80231"}, {"street" : "pine drive", "city" : "santa clara", "zip" : "95054"}]}
scala> dispatch.json.JsValue.toJson(res8)
res9: String = {"name" : "Debasish Ghosh", "addresses" : [{"street" : "monroe st", "city" : "denver", "zip" : "80231"}, {"street" : "pine drive", "city" : "santa clara", "zip" : "95054"}]}
scala> fromjson[Contact](res8)
res10: Contact = Contact(Debasish Ghosh,List(Address(monroe st,denver,80231), Address(pine drive,santa clara,95054)))
scala> res10 == contact
res11: Boolean = true
As can be seen from above, type class implementations for all built-in types like List
etc. are automatically made available through implicits. For your own types, you need to define your Format
implementation (as we did with Address
above).
Here's a sample session at the REPL:
scala> import sjson.json._
import sjson.json._
scala> import DefaultProtocol._
import DefaultProtocol._
scala> val t1 = ("debasish", 12)
t1: (java.lang.String, Int) = (debasish,12)
scala> import JsonSerialization._
import JsonSerialization._
scala> tojson(t1)
res1: dispatch.json.JsValue = ["debasish", 12]
scala> dispatch.json.JsValue.toJson(res1)
res2: String = ["debasish", 12]
scala> fromjson[Tuple2[String, Int]](res1)
res3: (String, Int) = (debasish,12)
scala> res3 == t1
res4: Boolean = true
scala> import scala.collection._
import scala.collection._
scala> val s = mutable.Set(12, 13, 10, 23, 25)
s: scala.collection.mutable.Set[Int] = Set(12, 25, 23, 13, 10)
scala> tojson(s)
res5: dispatch.json.JsValue = [13, 25, 12, 10, 23]
scala> dispatch.json.JsValue.toJson(res5)
res6: String = [13, 25, 12, 10, 23]
scala> fromjson[mutable.Set[Int]](res5)
res7: scala.collection.mutable.Set[Int] = Set(12, 25, 23, 13, 10)
scala> s == res7
res8: Boolean = true
scala> import scala.collection._
import scala.collection._
scala> val t = immutable.Set(12, 13, 10, 23, 25)
t: scala.collection.immutable.Set[Int] = Set(12, 23, 13, 10, 25)
scala> tojson(t)
res9: dispatch.json.JsValue = [12, 23, 13, 25, 10]
scala> dispatch.json.JsValue.toJson(res9)
res10: String = [12, 23, 13, 25, 10]
scala> fromjson[immutable.Set[Int]](res9)
res11: scala.collection.immutable.Set[Int] = Set(12, 23, 13, 10, 25)
scala> t == res11
res12: Boolean = true
scala> import sjson.json._
import sjson.json._
scala> import DefaultProtocol._
import DefaultProtocol._
scala> import JsonSerialization._
import JsonSerialization._
scala> val m = Map("100" -> "dg", "200" -> "mc")
m: scala.collection.immutable.Map[java.lang.String,java.lang.String] = Map((100,dg), (200,mc))
scala> tojson(m)
res1: dispatch.json.JsValue = {"100" : "dg", "200" : "mc"}
scala> dispatch.json.JsValue.toJson(res1)
res2: String = {"100" : "dg", "200" : "mc"}
scala> fromjson[Map[String, String]](res1)
res3: Map[String,String] = Map((100,dg), (200,mc))
scala> res3 == m
res4: Boolean = true
You can do that too. Here's a sample REPL session:
scala> import sjson.json._
import sjson.json._
scala> import JsonSerialization._
import JsonSerialization._
scala> import DefaultProtocol._
import DefaultProtocol._
scala> case class Address(street: String, city: String, zip: String)
defined class Address
scala> implicit val AddressFormat: Format[Address] =
| asProduct3("street", "city", "zip")(Address)(Address.unapply(_).get)
AddressFormat: sjson.json.Format[Address] = sjson.json.Generic$$anon$4@eae692
scala> case class Base(no: String, name: String, addresses: Array[Address])
defined class Base
scala> implicit val BaseFormat: Format[Base] =
| asProduct3("no", "name", "addresses")(Base)(Base.unapply(_).get)
BaseFormat: sjson.json.Format[Base] = sjson.json.Generic$$anon$4@13f957a
scala> class Derived(no: String, name: String, addresses: Array[Address], special: Boolean) extends Base(no, name, addresses) {
| val specialFlag = special
| }
defined class Derived
scala> object DerivedProtocol extends DefaultProtocol {
| import dispatch.json._
| import JsonSerialization._
| implicit object DerivedFormat extends Format[Derived] {
| def reads(json: JsValue): Derived = {
| val b = fromjson[Base](json)
| json match {
| case JsObject(m) =>
| new Derived(b.no, b.name, b.addresses,
| fromjson[Boolean](m(JsString("specialFlag"))))
| case _ => throw new RuntimeException("JsObject expected")
| }
| }
| def writes(a: Derived): JsValue = {
| val o = tojson(a: Base)
| val JsObject(m) = o
| JsObject(m ++ List((tojson("specialFlag").asInstanceOf[JsString], tojson(a.specialFlag))))
| }
| }
| }
defined module DerivedProtocol
scala> import DerivedProtocol._
import DerivedProtocol._
scala> val sa = new Derived("123", "debasish ghosh",
Array(Address("monroe st", "denver", "80231"), Address("tamarac st", "boulder", "80231")), true)
sa: Derived = Base(123,debasish ghosh,[LAddress;@ad7990)
scala> val acc = fromjson[Derived](tojson(sa))
acc: Derived = Base(123,debasish ghosh,[LAddress;@a528bc)