Argonauta.io:cómo cambiar el nombre de la propiedad json a Derecha/Izquierda en caso de que la clase contenga Cualquiera
Pregunta
En Argonaut, ¿cómo se puede cambiar fácilmente el nombre de la propiedad JSON correspondiente en los casos en que una clase de caso contiene cualquiera de los dos?
Por ejemplo, dada esta definición:
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")
convirtiendo un FooBar
a JSON como FooBar(Right(Bar("hello"))).asJson.spaces4
resulta en lo siguiente:
{
"e" : {
"Right" : {
"b" : "hello"
}
}
}
¿Cuál es la forma más sencilla de cambiar el nombre de "Derecha" a algo más significativo en el resultado anterior?(Mi escenario real tiene muchas clases de casos con muchos Ambos, por lo que busco la forma más concisa posible).
Solución
He aquí un enfoque razonablemente sencillo:
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")))
)
Y luego:
val fooOrBar = namedEitherCodec[Foo, Bar]("Foo", "Bar")
implicit def FooBarCodecJson: CodecJson[FooBar] = casecodec1(
FooBar.apply, FooBar.unapply
)("e")(fooOrBar, fooOrBar)
También podrías hacer el fooOrBar
Las instancias de clase de tipo implícitas, pero anuladoras de esa manera, tienden a ser mal vistas.
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow