Argonaute.io :comment renommer la propriété json pour Droite/Gauche dans le cas où la classe contient Soit
Question
Dans Argonaut, comment renommer facilement le nom de la propriété JSON correspondante dans les cas où une classe de cas contient un Soit.
Par exemple, étant donné cette définition :
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")
convertir un FooBar
en JSON comme FooBar(Right(Bar("hello"))).asJson.spaces4
aboutit à ce qui suit :
{
"e" : {
"Right" : {
"b" : "hello"
}
}
}
Quelle est la manière la plus simple de renommer le « Droit » en quelque chose de plus significatif dans la sortie ci-dessus ?(Mon scénario actuel comporte de nombreuses classes de cas avec de nombreux Soit, je recherche donc la manière la plus concise possible.)
La solution
Voici une approche assez simple :
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")))
)
Et puis:
val fooOrBar = namedEitherCodec[Foo, Bar]("Foo", "Bar")
implicit def FooBarCodecJson: CodecJson[FooBar] = casecodec1(
FooBar.apply, FooBar.unapply
)("e")(fooOrBar, fooOrBar)
Vous pourriez également faire le fooOrBar
implicites, mais les instances de classe de types prioritaires de cette manière ont tendance à être mal vues.