Argonaut.io:So benennen Sie die JSON-Eigenschaft für „Rechts/Links“ um, falls eine Klasse „Entweder“ enthält
Frage
Wie kann man in Argonaut den entsprechenden JSON-Eigenschaftsnamen einfach umbenennen, wenn eine Fallklasse ein Entweder enthält?
Nehmen wir zum Beispiel diese Definition:
case class Foo(f: String)
case class Bar(b: String)
case class FooBar(e: Either[Foo, Bar])
implicit def FooCodecJson: CodecJson[Foo] = casecodec1(Foo.apply, Foo.unapply)("f")
implicit def BarCodecJson: CodecJson[Bar] = casecodec1(Bar.apply, Bar.unapply)("b")
implicit def FooBarCodecJson: CodecJson[FooBar] = casecodec1(FooBar.apply, FooBar.unapply)("e")
Umwandeln von a FooBar
zu JSON wie FooBar(Right(Bar("hello"))).asJson.spaces4
ergibt folgendes:
{
"e" : {
"Right" : {
"b" : "hello"
}
}
}
Was ist der einfachste Weg, das „Recht“ in der obigen Ausgabe in etwas aussagekräftigeres umzubenennen?(Mein aktuelles Szenario hat viele Fallklassen mit vielen Entweder, daher suche ich nach einem möglichst prägnanten Weg.)
Lösung
Hier ist ein einigermaßen einfacher Ansatz:
def renameFields(replacements: (JsonField, JsonField)*)(json: Json) =
json.withObject(obj =>
replacements.foldLeft(obj) {
case (acc, (before, after)) =>
acc(before).map(v => (acc - before) + (after, v)).getOrElse(acc)
}
)
def renamedEitherCodec[A, B](leftName: String, rightName: String)(implicit
ee: EncodeJson[Either[A, B]],
de: DecodeJson[Either[A, B]]
) = CodecJson[Either[A, B]](
e => renameFields("Left" -> leftName, "Right" -> rightName)(ee(e)),
c => de(c.withFocus(renameFields(leftName -> "Left", rightName -> "Right")))
)
Und dann:
val fooOrBar = namedEitherCodec[Foo, Bar]("Foo", "Bar")
implicit def FooBarCodecJson: CodecJson[FooBar] = casecodec1(
FooBar.apply, FooBar.unapply
)("e")(fooOrBar, fooOrBar)
Du könntest auch das machen fooOrBar
implizit, aber das Überschreiben von Typklasseninstanzen auf diese Weise wird tendenziell verpönt.
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow