Search code examples
jsonscalacirce

How to parse an variant Json using Circe library with Scala?


I'm trying to create a decoder for my Json model using case classes but i cannot find the way to decode a variant list of jsons.

object CirceTester {

  def main(args: Array[String]): Unit = {

    val json = """{
  "foo": "bar",
  "baz": "123.34",
  "list of stuff": [ "4", "5", "6","24545","435.030" ],
  "jsonlist": [ {"name":"Jesus","age":20},{"name":"Pedro","age":45}]
}
"""


     case class Person(name:String,age:Int)

    implicit val decodePerson : Decoder[Person] = {

      Decoder.forProduct2("name","age")(Person.apply)

    }

    val parsedJson = parse(json)


    val list = parsedJson match {
      case Left(parsingFailure) => throw new Exception("Failed to parse Json")
      case Right(parsedJson) => parsedJson.hcursor.downField("jsonlist").as[List[Person]]


    }

  }       
}    

If the Json is written this way it works fine but if Json has a list of variant Jsons which is the case of jsonlist, the code will fail.

For example

val json = """{
  "foo": "bar",
  "baz": "123.34",
  "list of stuff": [ "4", "5", "6","24545","435.030" ],
  "jsonlist": [ {"name":"Jesus","age":20},{"name":"Pedro"}]
}
""" 

In this case, the second element of jsonlist is another Json that lacks the field "age", and as I said it will throw an Exception. Can i manage to parse that nested Json even if it doesn't follow exactly the structure of the case class


Solution

  • As it clear now that questions stands about reading optional values from json.

    Changing model to fit json structure you trying to parse is one of the best choices here. So in this case age filed must to be optional: case class Person(name: String, age: Option[Int]).

    If you cant change your Person definition you can define intermediate case class PersonRecord(name: String, age: Option[Int]) and write custom def toPerson: Person method inside - this way it is clearer then creating custom logic in json readers.