json - 解析Json时如何解决Circe中的递归解码?
问题描述
我想使用 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 字符串解析为我的模型时,我收到如下错误:
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)
如果您按照这些步骤进入文档直到最后一个,您将获得以下对象:
{
"task_id": "5",
"random_prop": "...",
"type": "test",
"attributes": {
"name": "C"
}
}
最后一步是失败的,它是DownField(dependencies)
,这是有道理的,因为该对象没有dependencies
字段。
有几种方法可以解决此问题。第一个是更改您的 JSON 表示,以便entity
数组中的每个对象都有一个dependencies
字段,即使它只是"dependencies": {}
. 如果您不想或不能更改您的 JSON,您可以让该dependencies
成员成为一个Option[Map[String, Tasks]]
(我刚刚确认这特别适用于您的情况)。您还可以定义一个自定义Map
解码器,将缺失的字段解码为空地图,但这是一种更具侵入性的方法,我个人不建议这样做。
推荐阅读
- c++ - shared_ptr
到数组的一个元素(shared_ptr ) - reactjs - 为什么我的 React App 垂直显示引导导航栏?
- c# - 设置 EntityState = Unchanged 一次,不会跟踪所有相同的对象
- angular - Angular - ngrx,switchMap 出错进一步订阅未触发
- javascript - V-Model 中的条件语句
- math - 求解递归:T(n) = T(n - 1) + T(n - 2) + 3
- javascript - 根据传递的 props 为组件创建类型
- reactjs - 如何为 react-select 组件的每个选项设置不同的样式?
- opc-ua - 什么是 OPC-UA 中的节点?
- javascript - 扩展js原型,参数被强制类型