Cómo implementar escrituras Json implícitas de objetos incrustados en Play Framework 2.x
scala playframework (1)
Hay dos clases de Foo
y Bar
. Foo
contiene un campo de Bar
. La pregunta es, ¿cómo implemento un json Writes
implícito para la clase Foo
?
Aquí está el código:
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
)
}
}
}
Cuando intento compilar, me sale el siguiente error:
No se ha encontrado ningún deserializador Json para modelos de tipo. Barra. Trate de implementar una escritura implícita o un formato para este tipo.
No entiendo este error del compilador, ya que implementé una escritura implícita para la clase models.Bar. ¿Cuál es el problema aquí?
Es una cuestión de visibilidad, al declarar las Escrituras implícitas [Foo] no está haciendo visibles las Escrituras [Barras] implícitas:
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
}
}
Además, si está utilizando Play 2.1+, asegúrese de verificar el nuevo uso de las macros de 2.10: http://www.playframework.com/documentation/2.1.0/ScalaJsonInception
Si está satisfecho con el uso de las clases de casos y los nombres de val / vars que se utilizan como claves en la salida json, como en su caso BTW, entonces puede usar las dos líneas de una línea:
implicit val barFormat = Json.writes[Bar]
implicit val fooFormat = Json.writes[Foo]
Eso te dará el equivalente exacto:
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
}
}