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!
5 comments:
Looks very impressive, and demonstrates the power of scala very well !
Looks neat. Your choice of fonts, however, makes my eyes bleed.
Cute!
Just a couple of nitpicks :
.in and .out are confusing and their directionality is really in the eye of the reader (I would've imagined them to be behaving exactly the other way around)
The usage of JsBean.fromJSON() and serializer.in(). Perhaps I'm confused - but is there a way to have similar API ? (there's a good likelihood I'm missing something here).
Small typo, there's a ")" in the URL pointing to Dispatch in the displayed README on http://github.com/debasishg/sjson/tree/master, it makes for a dead link. D'oh!
cheers!
@Rodney : thanks for pointing this out .. fixed!
Post a Comment