代码之家  ›  专栏  ›  技术社区  ›  Travis Brown

如何忽略json数组中的解码失败?

  •  4
  • Travis Brown  · 技术社区  · 7 年前

    假设我想将json数组中的一些值解码为case类 circe . 以下工作正常:

    scala> import io.circe.generic.auto._, io.circe.jawn.decode
    import io.circe.generic.auto._
    import io.circe.jawn.decode
    
    scala> case class Foo(name: String)
    defined class Foo
    
    scala> val goodDoc = """[{ "name": "abc" }, { "name": "xyz" }]"""
    goodDoc: String = [{ "name": "abc" }, { "name": "xyz" }]
    
    scala> decode[List[Foo]](goodDoc)
    res0: Either[io.circe.Error,List[Foo]] = Right(List(Foo(abc), Foo(xyz)))
    

    有时我解码的json数组包含- Foo -但形状的东西会导致解码错误:

    scala> val badDoc =
         |   """[{ "name": "abc" }, { "id": 1 }, true, "garbage", { "name": "xyz" }]"""
    badDoc: String = [{ "name": "abc" }, { "id": 1 }, true, "garbage", { "name": "xyz" }]
    
    scala> decode[List[Foo]](badDoc)
    res1: Either[io.circe.Error,List[Foo]] = Left(DecodingFailure(Attempt to decode value on failed cursor, List(DownField(name), MoveRight, DownArray)))
    

    如何编写一个解码器,忽略数组中无法解码到case类中的任何内容?

    1 回复  |  直到 7 年前
        1
  •  4
  •   Travis Brown    7 年前

    解决这个问题最直接的方法是使用一个解码器,该解码器首先尝试将每个值解码为 Foo ,然后返回到身份解码器,如果 解码器失败。新的 either Circe 0.9中的方法使其泛型版本实际上是一行:

    import io.circe.{ Decoder, Json }
    
    def decodeListTolerantly[A: Decoder]: Decoder[List[A]] =
      Decoder.decodeList(Decoder[A].either(Decoder[Json])).map(
        _.flatMap(_.left.toOption)
      )
    

    它的工作原理如下:

    scala> val myTolerantFooDecoder = decodeListTolerantly[Foo]
    myTolerantFooDecoder: io.circe.Decoder[List[Foo]] = io.circe.Decoder$$anon$21@2b48626b
    
    scala> decode(badDoc)(myTolerantFooDecoder)
    res2: Either[io.circe.Error,List[Foo]] = Right(List(Foo(abc), Foo(xyz)))
    

    要分解步骤:

    • Decoder.decodeList 表示“定义一个列表解码器,尝试使用给定的解码器解码每个json数组值”。
    • Decoder[A].either(Decoder[Json] 说“首先尝试将值解码为 A ,如果无法将其解码为 Json 值(将始终成功),并将结果(如果有)作为 Either[A, Json] “。
    • .map(_.flatMap(_.left.toOption)) 说“把结果列表 或者[a,json] 值并删除所有 Right S”。

    它以一种相当简洁的作曲方式完成了我们想要的。在某种程度上,我们可能希望将其捆绑到circe本身的实用程序方法中,但目前写出这个显式版本还不算太糟。