Подтвердить что ты не робот

Как реализовать неявные Json Writes встроенного объекта в Play Framework 2.x

существуют два класса Foo и Bar. Foo содержит поле Bar. Вопрос в том, как реализовать неявный json Writes для класса Foo?

Вот код:

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
      )
    }
  }
}

Когда я пытаюсь скомпилировать, я получаю следующую ошибку:

Нет десанциализатора Json для моделей типов. Попробуйте реализовать неявные Writes или Format для этого типа.

Я не понимаю эту ошибку компилятора, так как я реализовал неявный Writes для models.Bar. В чем проблема?

4b9b3361

Ответ 1

Вопрос о видимости, при объявлении неявных Writes [Foo], вы не делаете видимыми неявные Writes [Bar]:

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
  }
}

Кроме того, если вы используете Play 2.1+, обязательно ознакомьтесь с новым использованием макросов 2.10: http://www.playframework.com/documentation/2.1.0/ScalaJsonInception

Если вы довольны использованием классов case и имен val/vars, которые используются в качестве ключей в выводе json, как в вашем случае BTW, вы можете использовать два однострочных:

implicit val barFormat = Json.writes[Bar]
implicit val fooFormat = Json.writes[Foo]

Это даст вам точный эквивалент:

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] = [email protected]

scala> implicit val fooWrites = Json.writes[Foo]
fooWrites: play.api.libs.json.OWrites[Foo] = [email protected]

scala> Json.prettyPrint(Json.toJson(Foo("23", Bar("x", 1))))
res0: String = 
{
  "id" : "23",
  "bar" : {
    "x" : "x",
    "y" : 1
  }
}