Schreiben Sie mit den Scala-JSON-Kombinatoren von Play (2.2) einen beliebigen Wert, der in einer Case-Klasse nicht gefunden wurde

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

Frage

Ich möchte a implementieren Writes das ein JSON-Objekt ausgibt, das in der zu serialisierenden Klasse nicht gefunden wird.

Für die Fallklasse:

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

Ich möchte Folgendes produzieren:

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

Der naive erste Versuch war:

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

Natürlich lässt sich das nicht wie folgt kompilieren and Anrufe erzeugen a CanBuild3 Und Foo'S unapply erzeugt ein Tuple2.Ich hatte darüber nachgedacht, dem Ergebnis einen Wert anzuhängen und so einen zu erzeugen Tuple3, aber was ich gefunden habe sieht ziemlich schlecht aus und das Sprachbetreuer werden es nicht implementieren.

Es gibt Möglichkeiten, dies zu umgehen, aber ich möchte meine Modellklassen lieber nicht mit diesen Dekoratorwerten verunreinigen, die ich dem resultierenden JSON hinzufügen möchte.

Irgendwelche Vorschläge?

Es lohnt sich, Sie zu erwähnen dürfen Gehen Sie in die andere Richtung und geben Sie Werte mit Reads.pure für Fälle, in denen ein Wert nicht in JSON vorhanden ist, aber durch das resultierende Objekt angegeben wird.

War es hilfreich?

Lösung

Sie können dies ganz einfach tun, indem Sie ein wenig entzuckern:

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

Der unlift(Foo.unapply) ist nur eine ausgefallene Möglichkeit, eine Funktion von a zu erhalten Foo zu einem Tupel der Art, die für den vorangehenden applikativen Builder-Ausdruck erforderlich ist, und Sie können es durch Ihre eigene Funktion ersetzen, die alles hinzufügen kann, was Sie möchten.

Wenn du Wirklich wollte eine noch sauberere Syntax, die Sie verwenden könnten Formlos:

import shapeless.syntax.std.tuple._

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

Es ist wunderschön, aber vielleicht übertrieben.

Andere Tipps

Eine andere Möglichkeit besteht darin, einen Objekt-Builder zu verwenden, der ein implementiert unapply das gibt die zusätzlichen Werte zurück.Dadurch werden die Schreibvorgänge sauberer, es wird jedoch ein neues Objekt hinzugefügt.Ich habe dies jedoch als nützlich empfunden, da sowohl die Apply- als auch die Unapply-Methode zum zusätzlichen Einmassieren von Daten in das endgültige Objekt verwendet werden können (z. B.: https://stackoverflow.com/a/22504468/1085606)

Beispiel:

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))
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top