there are two classes Foo and Bar. Foo contains a field of Bar. The question is, how do I implement an implicit json Writes for class Foo?
Here is the code:
package models
import play.api.libs.json._
case class Foo(id: String, bar: Bar)
object Foo {
  implicit val implicitFooWrites = new Writes[Foo] {
    def writes(foo: Foo): JsValue = {
      Json.obj(
        "id" -> foo.id,
        "bar" -> foo.bar
      )
    }
  }
}
case class Bar(x: String, y: Int)
object Bar {
  implicit val implicitBarWrites = new Writes[Bar] {
    def writes(bar: Bar): JsValue = {
      Json.obj(
        "x" -> bar.x,
        "y" -> bar.y
      )
    }
  }
}
When I try to compile, I get the following error:
No Json deserializer found for type models.Bar. Try to implement an implicit Writes or Format for this type.
I don't understand this compiler error, since I implemented an implicit Writes for models.Bar class. What is the problem here?
It's a question of visibility, when declaring the implicit Writes[Foo] you are not making visible the implicit Writes[Bar] to it:
scala> :paste
// Entering paste mode (ctrl-D to finish)
import play.api.libs.json._
case class Bar(x: String, y: Int)
object Bar {
  implicit val implicitBarWrites = new Writes[Bar] {
    def writes(bar: Bar): JsValue = {
      Json.obj(
        "x" -> bar.x,
        "y" -> bar.y
      )
    }
  }
}
case class Foo(id: String, bar: Bar)
object Foo {
  import Bar._
  implicit val implicitFooWrites = new Writes[Foo] {
    def writes(foo: Foo): JsValue = {
      Json.obj(
        "id" -> foo.id,
        "bar" -> foo.bar
      ) 
    } 
  }     
}
// Exiting paste mode, now interpreting.
import play.api.libs.json._
defined class Bar
defined module Bar
defined class Foo
defined module Foo
scala> Json.prettyPrint(Json.toJson(Foo("23", Bar("x", 1))))
res0: String = 
{
  "id" : "23",
  "bar" : {
    "x" : "x",
    "y" : 1
  }
}
Also, if you're using Play 2.1+ make sure to check out the brand new use of 2.10's macros: http://www.playframework.com/documentation/2.1.0/ScalaJsonInception
If you're happy with the use of the case classes and the val/vars' names being used as keys in the json output, as in your case BTW, then you can use the two one-liners:
implicit val barFormat = Json.writes[Bar]
implicit val fooFormat = Json.writes[Foo]
That will give you the exact equivalent:
scala> import play.api.libs.json._
import play.api.libs.json._
scala> case class Bar(x: String, y: Int)
defined class Bar
scala> case class Foo(id: String, bar: Bar)
defined class Foo
scala> implicit val barWrites = Json.writes[Bar]
barWrites: play.api.libs.json.OWrites[Bar] = play.api.libs.json.OWrites$$anon$2@257cae95
scala> implicit val fooWrites = Json.writes[Foo]
fooWrites: play.api.libs.json.OWrites[Foo] = play.api.libs.json.OWrites$$anon$2@48f97e2a
scala> Json.prettyPrint(Json.toJson(Foo("23", Bar("x", 1))))
res0: String = 
{
  "id" : "23",
  "bar" : {
    "x" : "x",
    "y" : 1
  }
}
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With