【问题标题】:Argonaut.io: how to rename json property for Right/Left in case class containing EitherArgonaut.io:如何重命名 Right/Left 的 json 属性,以防万一包含 Either
【发布时间】:2014-04-11 04:50:12
【问题描述】:

在 Argonaut 中,如何在案例类包含 Either 的情况下轻松重命名相应的 JSON 属性名称。

例如,给定这个定义:

  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")

FooBar 转换为像FooBar(Right(Bar("hello"))).asJson.spaces4 这样的JSON 会产生以下结果:

{
    "e" : {
        "Right" : {
            "b" : "hello"
        }
    }
}

在上面的输出中将“Right”重命名为更有意义的名称的最简单方法是什么? (我的实际场景有很多案例类,其中有很多,所以我正在寻找最简洁的方法。)

【问题讨论】:

    标签: json scala either argonaut


    【解决方案1】:

    这是一个相当简单的方法:

    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")))
    )
    

    然后:

    val fooOrBar = namedEitherCodec[Foo, Bar]("Foo", "Bar")
    
    implicit def FooBarCodecJson: CodecJson[FooBar] = casecodec1(
      FooBar.apply, FooBar.unapply
    )("e")(fooOrBar, fooOrBar)
    

    您也可以将 fooOrBar 设为隐式,但以这种方式覆盖类型类实例往往会令人不悦。

    【讨论】:

      猜你喜欢
      • 2021-01-18
      • 2018-10-09
      • 1970-01-01
      • 2021-11-12
      • 1970-01-01
      • 2019-03-14
      • 1970-01-01
      • 1970-01-01
      • 2013-11-11
      相关资源
      最近更新 更多