Play Framework 2.4 Writes[-A] vs OWrites[-A], Format[A] vs OFormat[A]. Purpose? Play Framework 2.4 Writes[-A] vs OWrites[-A], Format[A] vs OFormat[A]. Purpose? json json

Play Framework 2.4 Writes[-A] vs OWrites[-A], Format[A] vs OFormat[A]. Purpose?


Often you know that an encoder will always produce a JSON object (as opposed to an arbitrary JSON value). Tracking this fact in the type system makes it possible to work with the output of such an encoder without jumping through the hoops that would be normally be necessary.

For example, suppose we've got a simple class:

class Foo(val name: String, val age: Long)

And we write a Writes instance like this:

import play.api.libs.functional.syntax._import play.api.libs.json._implicit val fooWrites: Writes[Foo] = (  (__ \ 'name).write[String] and (__ \ 'age).write[Long])(foo => (foo.name, foo.age))

Now we can write the following:

scala> val json = fooWrites.writes(new Foo("McBar", 101))json: play.api.libs.json.JsValue = {"name":"McBar","age":101}

Now suppose that for whatever reason we want to get a list of the field names. We have to write something like this:

scala> json.as[JsObject].keysres0: scala.collection.Set[String] = Set(name, age)

Instead of this:

scala> json.keys<console>:17: error: value keys is not a member of play.api.libs.json.JsValue              json.keys                   ^

But of course we know that json will always be a JsObject. The problem is that the compiler doesn't. OWrites fixes this.

implicit val fooWrites: OWrites[Foo] = (   (__ \ 'name).write[String] and (__ \ 'age).write[Long])(foo => (foo.name, foo.age))

And then:

scala> val json = fooWrites.writes(new Foo("McBar", 101))json: play.api.libs.json.JsObject = {"name":"McBar","age":101}scala> json.keysres1: scala.collection.Set[String] = Set(name, age)

The output of writes on OWrites is statically typed as a JsObject, so we can use .keys without the unsafe as[JsObject] cast.

(As a side note, I'm not personally a fan of making method return types more specific in subclasses, and I've taken a slightly different approach to solving this problem in circe.)