Scrivi un valore arbitrario non trovato in una cassa di classe utilizzando i combinatori Scala JSON di Play (2.2)

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

Domanda

Mi piacerebbe implementare un Writes che emette un oggetto JSON che non è stato trovato nella classe che viene serializzato.

per la cassa della cassa:

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

Sto cercando di produrre:

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

Il primo tentativo naïve era:

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

Naturalmente, che non si compilerà come le successive chiamate and producono un CanBuild3 e Footagcode di unapply producono un Tuple2. Ho guardato nell'aggiunta di un valore al risultato, producendo un Tuple3, ma quello che ho trovato Sembra piuttosto male e I manutentori della lingua non lo impleniranno .

Ci sono modi per aggirare questo, ma preferirei non inquinare le mie lezioni del modello con questi valori del decoratore che vorrei aggiungere al JSON risultante.

Qualche suggerimento?

Vale la pena notare che può Vai dall'altra direzione, fornendo valori con Reads.pure per i casi in cui un valore non esiste in JSON ma è specificato dall'oggetto risultante.

È stato utile?

Soluzione

Puoi farlo abbastanza diretto dal disugurazione di un po ':

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

Il unlift(Foo.unapply) è solo un modo elegante per ottenere una funzione da un Foo a una tupla del tipo richiesto dall'espressione precedente del costruttore applicativo, e puoi sostituirlo con la propria funzione che può aggiungere qualsiasi cosa desideri. Se you veramente voleva persino la sintassi più pulita, è possibile utilizzare Sforzo :

import shapeless.syntax.std.tuple._

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

È bello, ma può essere eccessivo.

Altri suggerimenti

Un'altra opzione è utilizzare un generatore di oggetti che implementa un unapply che restituisce i valori extra.Questo rende il pulitore scrive, ma aggiunge un nuovo oggetto.Ho trovato utile anche se sia il metodo applicato e inappropriato può essere utilizzato per ulteriori massaggi di dati nell'oggetto finale (ad esempio: https://stackoverflow.com/a/22504468/1085606 )

Esempio:

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

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top