Search code examples
jsonscalacirce

Parsing recursive JSON structure with Lists in Scala


I've got the following JSON structure and I can't find a good way to parse it in Scala (I'm using circe BTW):

{
  "name": "xx",
  "args": [
    {"name":"xy", "args": []},
    [
      {"name":"xy", "args": []},
      {"name":"xy", "args": [[]]}
    ],
    [
      [
        {"name":"xy", "args": [{"name":"xy", "args": []}]}
      ]
    ]
  ]
}

Basically, it's a recursive structure that can contain either object, or list of objects, or list of lists, or list of lists of lists... or objects and lists.

How can I handle that? I'm thinking about some recursive types but I'm not sure about that.


Solution

  • You need to model that as an ADT and derive a custom Decoder like this:

    import io.circe.{Decoder, DecodingFailure, parser}
    import io.circe.generic.semiauto.deriveDecoder
    
    sealed trait Arg
    object Arg {
      final case class OneArg(name: String, args: List[Arg]) extends Arg
      final case class MultipleArgs(args: List[Arg]) extends Arg
      
      private implicit final val OneArgDecoder: Decoder[OneArg] = deriveDecoder
      
      implicit final val ArgDecoer: Decoder[Arg] =
        Decoder.instance[Arg] { cursor =>
          cursor.focus match {
            case Some(json) =>
              // Here you may also ask if it is an array before to attempt to get it as a List[arg], and if not then provide a custom failure.
              if (json.isObject) json.as[OneArg]
              else json.as[List[Arg]].map(MultipleArgs)
            
            case None =>
              Left(DecodingFailure("Empty cursor", cursor.history))
          }
        }
    }
    

    Which can be used to decode your JSON: https://scastie.scala-lang.org/BalmungSan/W0lLBYRzTIS3PC4E5i0wXA/26