假设我想用circe将JSON数组中的一些值解码为case类。下面的代码运行得很好:
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
-shaped内容,这会导致解码错误:
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类中的东西呢?
发布于 2018-06-05 04:19:06
解决此问题的最直接方法是使用解码器,该解码器首先尝试将每个值解码为Foo
,然后在Foo
解码器失败时回退到标识解码器。circe 0.9中的新either
方法使它的泛型版本实际上是一行程序:
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
说“定义一个列表解码器,尝试使用给定的解码器来解码value".Decoder[A].either(Decoder[Json]
说的每个JSON数组”,首先尝试将值解码为A
,如果失败,则将其解码为Json
值(这将总是成功的),然后按照JSON所说的返回结果(如果有的话)“获取Either[A, Json]
值的结果列表并删除所有JSON…它以一种相当简洁的组合方式做了我们想要的事情。在某种程度上,我们可能想把它捆绑到circe本身的一个实用方法中,但现在写出这个显式版本还不算太差。
https://stackoverflow.com/questions/50688169
复制相似问题