Как разобрать вариант Json с помощью библиотеки Circe на Scala?

Я пытаюсь создать декодер для моей модели Json, используя классы case, но я не могу найти способ декодировать список вариантов 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]]


    }

  }       
}    

Если Json написан таким образом, он работает нормально, но если у Json есть список вариантов Jsons, как в случае jsonlist, код завершится ошибкой.

Например

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

В этом случае второй элемент jsonlist - это еще один Json, в котором отсутствует поле age, и, как я уже сказал, он вызовет исключение. Могу ли я проанализировать этот вложенный Json, даже если он не соответствует в точности структуре класса case


person Jesus Vasquez    schedule 02.11.2018    source источник
comment
Для необязательных полей существует Option. Есть ли причины, по которым вы не хотите преобразовывать свою модель в case class Person(name: String, age: Option[Int])?   -  person Yevhenii Popadiuk    schedule 02.11.2018
comment
Большое спасибо @YevheniiPopadiuk, я не знал, что могу использовать Option в этом случае, он отлично работает   -  person Jesus Vasquez    schedule 02.11.2018


Ответы (1)


Теперь ясно, что возникают вопросы о чтении необязательных значений из json.

Изменение модели в соответствии со структурой json, которую вы пытаетесь проанализировать, - один из лучших вариантов. Таким образом, в этом случае поле age должно быть необязательным: case class Person(name: String, age: Option[Int]).

Если вы не можете изменить свое Person определение, вы можете определить промежуточный case class PersonRecord(name: String, age: Option[Int]) и написать собственный метод def toPerson: Person внутри - так он будет более понятным, чем создание собственной логики в читателях json.

person Yevhenii Popadiuk    schedule 02.11.2018