Escriba un valor arbitrario que no se encuentre en una clase de caso utilizando los combinadores Scala JSON de Play (2.2)

StackOverflow https://stackoverflow.com//questions/23019485

Pregunta

Me gustaría implementar un Writes que emite un objeto JSON que no se encuentra en la clase que se está serializando.

Para clase de caso:

case class Foo(i:Int, s:String)

Estoy buscando producir:

{
  "i": <int>,
  "s": "<string>",
  "other": "Some value."
}

El primer intento ingenuo fue:

val writes: Writes[Foo] = ((
  (__ \ "i").write[Int] and
    (__ \ "s").write[String] and
    (__ \ "other").write("Some value.")
  )(unlift(Foo.unapply))

Naturalmente, eso no se compilará como el siguiente and las llamadas producen un CanBuild3 y Foo's unapply produce un Tuple2.Había considerado agregar un valor al resultado, produciendo un Tuple3, pero lo que he encontrado se ve bastante mal y el Los mantenedores del idioma no lo implementarán..

Hay formas de solucionar este problema, pero prefiero no contaminar mis clases de modelo con estos valores de decorador que me gustaría agregar al JSON resultante.

¿Alguna sugerencia?

vale la pena destacarte poder ir en otra dirección, aportando valores con Reads.pure para casos en los que un valor no existe en JSON pero está especificado por el objeto resultante.

¿Fue útil?

Solución

Puedes hacer esto de manera bastante sencilla desazucarando un poco:

val writes: Writes[Foo] = (
  (__ \ "i").write[Int] and
  (__ \ "s").write[String] and
  (__ \ "other").write[String]
)(foo => (foo.i, foo.s, "Some value."))

El unlift(Foo.unapply) es sólo una forma elegante de obtener una función de un Foo a una tupla del tipo requerido por la expresión del generador de aplicaciones anterior, y puede reemplazarla con su propia función que puede agregar lo que desee.

Si usted en realidad Si quisieras una sintaxis aún más limpia, podrías usar Informe:

import shapeless.syntax.std.tuple._

val writes: Writes[Foo] = (
  (__ \ "i").write[Int] and
  (__ \ "s").write[String] and
  (__ \ "other").write[String]
)(_ :+ "Some value.")

Es hermoso, pero puede que sea excesivo.

Otros consejos

Otra opción es utilizar un generador de objetos que implemente un unapply que devuelve los valores adicionales.Esto hace que las escrituras sean más limpias, pero agrega un nuevo objeto.Sin embargo, esto me ha resultado útil, ya que tanto el método de aplicar como el de cancelar la aplicación se pueden usar para realizar un masaje adicional de datos en el objeto final (por ejemplo: https://stackoverflow.com/a/22504468/1085606)

Ejemplo:

case class Foo(i: Int, s: String)

object FooBuilder {
  def unapply(foo: Foo): Option[(Int, String, String)] = {
    Some((foo.i, foo.s, "Some extra value"))
  }
}

val writes: Writes[Foo] = ((
  (__ \ "i").write[Int] and
    (__ \ "s").write[String] and
    (__ \ "other").write[String]
  )(unlift(FooBuilder.unapply))
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top