Argonaut.io: Come rinominare JSON Property per il diritto / sinistra in caso di classe contenente entrambi
Domanda
ad Argonaut, come si rinomina facilmente il nome della proprietà JSON corrispondente in istanze in cui una cassa di cassa contiene unica.
Ad esempio, data questa definizione:
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")
.
Conversione di un FooBar
in JSON come FooBar(Right(Bar("hello"))).asJson.spaces4
Risultati:
{
"e" : {
"Right" : {
"b" : "hello"
}
}
}
.
Qual è il modo più semplice per rinominare il "giusto" a qualcosa di più significativo nell'output sopra?(Il mio vero scenario ha molte classi di case con molti etuithers, quindi sto cercando il modo più conciso possibile.)
Soluzione
Ecco un approccio ragionevolmente semplice:
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")))
)
.
E poi:
val fooOrBar = namedEitherCodec[Foo, Bar]("Foo", "Bar")
implicit def FooBarCodecJson: CodecJson[FooBar] = casecodec1(
FooBar.apply, FooBar.unapply
)("e")(fooOrBar, fooOrBar)
.
Potresti anche rendere le istanze Implicit fooOrBar
, ma sopravvalutarvi in questo modo tende ad essere disapprovazione.
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow