如何使用 Circe 库和 Scala 解析变体 Json?

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

我正在尝试使用 case classes 为我的 Json 模型创建解码器,但我找不到解码 json 变体列表的方法。

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 的第二个元素是另一个缺少字段 "age" 的 Json,正如我所说,它会抛出异常。我可以设法解析嵌套的 Json 即使它不完全遵循案例的结构 class

现在很清楚,关于从 json.

中读取可选值的问题

更改模型以适应您尝试解析的 json 结构是此处的最佳选择之一。所以在这种情况下 age filed 必须是可选的: case class Person(name: String, age: Option[Int])

如果您不能更改 Person 定义,您可以定义中间 case class PersonRecord(name: String, age: Option[Int]) 并在其中编写自定义 def toPerson: Person 方法 - 这样比在 [=23= 中创建自定义逻辑更清晰] 读者。