How do I ignore decoding failures in a JSON array? How do I ignore decoding failures in a JSON array? json json

How do I ignore decoding failures in a JSON array?


The most straightforward way to solve this problem is to use a decoder that first tries to decode each value as a Foo, and then falls back to the identity decoder if the Foo decoder fails. The new either method in circe 0.9 makes the generic version of this practically a one-liner:

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

It works like this:

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

To break down the steps:

  • Decoder.decodeList says "define a list decoder that tries to use the given decoder to decode each JSON array value".
  • Decoder[A].either(Decoder[Json] says "first try to decode the value as an A, and if that fails decode it as a Json value (which will always succeed), and return the result (if any) as a Either[A, Json]".
  • .map(_.flatMap(_.left.toOption)) says "take the resulting list of Either[A, Json] values and remove all the Rights".

…which does what we want in a fairly concise, compositional way. At some point we might want to bundle this up into a utility method in circe itself, but for now writing out this explicit version isn't too bad.