Here's the idea ..
I have a Scala object as ..
val addr = Address("Market Street", "San Francisco", "956871")
which I would like to store as JSON and retrieve as plain old Scala object. Here's the simple assertion that I would like to have as invariant ..
addr should equal(
serializer.in[Address](serializer.out(addr)))
There are situations, particularly when writing generic libraries, when I don't know what class to serialize into. I can do that as well ..
serializer.in[AnyRef](serializer.out(addr))
or just as ..
serializer.in(serializer.out(addr))
What you get back from is a
JsValue
, an abstraction of the JSON object model. You can use extractors to get back individual attributes ..val a = serializer.in[AnyRef](serializer.out(addr))
// use extractors
val c = 'city ? str
val c(_city) = a
_city should equal("San Francisco")
val s = 'street ? str
val s(_street) = a
_street should equal("Market Street")
val z = 'zip ? str
val z(_zip) = a
_zip should equal("956871")
Serialization of Embedded Objects
Suppose you have the following Scala classes .. Here
Contact
has an embedded Address
Map
..@BeanInfo
case class Contact(name: String,
@JSONTypeHint(classOf[Address])
addresses: Map[String, Address]) {
private [json] def this() = this(null, null)
override def toString = "name = " + name + " addresses = " +
addresses.map(a => a._1 + ":" + a._2.toString).mkString(",")
}
@BeanInfo
case class Address(street: String, city: String, zip: String) {
private [json] def this() = this(null, null, null)
override def toString = "address = " + street + "/" + city + "/" + zip
}
With SJSON, I can do the following ..
val a1 = Address("Market Street", "San Francisco", "956871")
val a2 = Address("Monroe Street", "Denver", "80231")
val a3 = Address("North Street", "Atlanta", "987671")
val c = Contact("Bob", Map("residence" -> a1, "office" -> a2, "club" -> a3))
val co = serializer.out(c)
// with class specified
c should equal(serializer.in[Contact](co))
// no class specified
val a = serializer.in[AnyRef](co)
// extract name
val n = 'name ? str
val n(_name) = a
"Bob" should equal(_name)
// extract addresses
val addrs = 'addresses ? obj
val addrs(_addresses) = a
// extract residence from addresses
val res = 'residence ? obj
val res(_raddr) = _addresses
// make an Address bean out of _raddr
val address = JsBean.fromJSON(_raddr, Some(classOf[Address]))
a1 should equal(address)
object r { def ># [T](f: JsF[T]) = f(a.asInstanceOf[JsValue]) }
// still better: chain 'em up
"Market Street" should equal(
(r ># { ('addresses ? obj) andThen ('residence ? obj) andThen ('street ? str) }))
Feel free to fork, contribute and enjoy!