繁体   English   中英

解析Json时如何解决Circe中的递归解码?

[英]How to resolve recursive decoding in Circe when parsing Json?

我想使用 Circa 解析 JSON 字符串。 您可以在下面找到输入 JSON 的示例。

这是一种递归数据。 所以我的属性entity包含实体的依赖关系。

我想解析对 map Map[String, Tasks]的依赖关系。

{
  "entity": [
    {
      "task_id": "X",
      "type": "test",
      "attributes": {
        "name": "A",
        "random_property_count": 1 // should be ignored
      },
      "dependencies": {
        "random_name_1": {
          "entity": [
            {
              "task_id": "907544AF",
              "type": "test",
              "attributes": {
                "name": "B",
                "random_attribute": "*"
              },
              "dependencies": {
                "random_name_2": {
                  "entity": [
                    {
                      "task_id": "5",
                      "random_prop": "...",  // should be ignored as it's not present in model
                      "type": "test",
                      "attributes": {
                        "name": "C"
                      }
                    }
                  ]
                }
              }
            }
          ]
        }
      }
    }
  ]
}

这是我的代码:

  case class Tasks (entity: Seq[Task])
  case class Task(task_id: String, `type`: String, attributes: Attributes, dependencies: Map[String, Tasks])
  case class Attributes(name: String)

  implicit val decodeTask: Decoder[Task] = deriveDecoder[Task]
  implicit val decodeTasks: Decoder[Tasks] = deriveDecoder[Tasks]
  implicit val decodeAttributes: Decoder[Attributes] = deriveDecoder[Attributes]

  val json = fromInputStream(getClass.getResourceAsStream("/json/example.json")).getLines.mkString
  val tasks = decode[Tasks](json)

  tasks match {
    case Left(failure) => println(failure)
    case Right(json)   => println(json)
  }

当我尝试将 JSON 字符串解析为 model 时,出现如下错误:

DecodingFailure(Attempt to decode value on failed cursor, List(DownField(dependencies), DownArray, DownField(entity), DownField(random_name_2), DownField(dependencies), DownArray, DownField(entity), DownField(random_name_1), DownField(dependencies), DownArray, DownField(entity)))

可能是什么问题?

DecodingFailure的第二个成员在这种情况下很有用,因为它提供了失败之前成功操作的历史以及失败操作本身(按时间倒序排列,最近的在前)。 您可以像这样打印历史记录(或者只是在DecodingFailure的字符串表示中检查它):

scala> import io.circe.DecodingFailure
import io.circe.DecodingFailure

scala> io.circe.jawn.decode[Tasks](doc) match {
     |   case Left(DecodingFailure(_, history)) => history.reverse.foreach(println)
     | }
DownField(entity)
DownArray
DownField(dependencies)
DownField(random_name_1)
DownField(entity)
DownArray
DownField(dependencies)
DownField(random_name_2)
DownField(entity)
DownArray
DownField(dependencies)

如果您在文档中执行这些步骤直到最后一个,您将获得以下 object:

{
  "task_id": "5",
  "random_prop": "...",
  "type": "test",
  "attributes": {
    "name": "C"
  }
}

最后一步是失败的,它是DownField(dependencies) ,这是有道理的,因为这个 object 没有dependencies项字段。

有几种方法可以解决此问题。 第一个是更改您的 JSON 表示,以便entity数组中的每个 object 都有一个dependencies项字段,即使它只是"dependencies": {} 如果您不想或无法更改 JSON,您可以将dependencies项成员设为Option[Map[String, Tasks]] (我刚刚确认这特别适用于您的情况)。 您还可以定义一个自定义Map解码器,将缺失的字段解码为空 map,但这是一种更具侵入性的方法,我个人不推荐。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM