gpt4 book ai didi

json - Argonaut:解码多态数组

转载 作者:行者123 更新时间:2023-12-02 01:19:47 25 4
gpt4 key购买 nike

我尝试为其编写 DecodeJson[T] 的 JSON 对象包含不同“类型”的数组(意味着其元素的 JSON 结构是变化的)。唯一的共同特征是 type 字段,可用于区分类型。所有其他领域都不同。示例:

{
...,
array: [
{ type: "a", a1: ..., a2: ...},
{ type: "b", b1: ...},
{ type: "c", c1: ..., c2: ..., c3: ...},
{ type: "a", a1: ..., a2: ...},
...
],
...
}

使用 argonaut,是否可以将 JSON 数组映射到 Scala Seq[Element],其中 ElementElementA 类型的合适案例类的父类(super class)型ElementB 等等?

我用 play-json 做了同样的事情,这很容易(基本上是一个评估 type 字段的 Reads[Element]并相应地转发到更具体的 Reads)。但是,我找不到使用 argonaut 执行此操作的方法。


编辑:示例

Scala 类型(我希望使用):

case class Container(id: Int, events: List[Event])

sealed trait Event
case class Birthday(name: String, age: Int) extends Event
case class Appointment(start: Long, participants: List[String]) extends Event
case class ... extends Event

JSON 实例(不在我的控制之下):

{
"id":1674,
"events": {
"data": [
{
"type": "birthday",
"name": "Jones Clinton",
"age": 34
},
{
"type": "appointment",
"start": 1675156665555,
"participants": [
"John Doe",
"Jane Doe",
"Foo Bar"
]
}
]
}
}

最佳答案

您可以创建一个小函数来帮助您构建处理这种格式的解码器。

请参阅下面的示例。

import argonaut._, Argonaut._

def decodeByType[T](encoders: (String, DecodeJson[_ <: T])*) = {
val encMap = encoders.toMap

def decoder(h: CursorHistory, s: String) =
encMap.get(s).fold(DecodeResult.fail[DecodeJson[_ <: T]](s"Unknown type: $s", h))(d => DecodeResult.ok(d))

DecodeJson[T] { c: HCursor =>
val tf = c.downField("type")

for {
tv <- tf.as[String]
dec <- decoder(tf.history, tv)
data <- dec(c).map[T](identity)
} yield data
}
}

case class Container(id: Int, events: ContainerData)
case class ContainerData(data: List[Event])

sealed trait Event
case class Birthday(name: String, age: Int) extends Event
case class Appointment(start: Long, participants: List[String]) extends Event

implicit val eventDecoder: DecodeJson[Event] = decodeByType[Event](
"birthday" -> DecodeJson.derive[Birthday],
"appointment" -> DecodeJson.derive[Appointment]
)

implicit val containerDataDecoder: DecodeJson[ContainerData] = DecodeJson.derive[ContainerData]
implicit val containerDecoder: DecodeJson[Container] = DecodeJson.derive[Container]

val goodJsonStr =
"""
{
"id":1674,
"events": {
"data": [
{
"type": "birthday",
"name": "Jones Clinton",
"age": 34
},
{
"type": "appointment",
"start": 1675156665555,
"participants": [
"John Doe",
"Jane Doe",
"Foo Bar"
]
}
]
}
}
"""

def main(args: Array[String]) = {
println(goodJsonStr.decode[Container])

// \/-(Container(1674,ContainerData(List(Birthday(Jones Clinton,34), Appointment(1675156665555,List(John Doe, Jane Doe, Foo Bar))))))
}

关于json - Argonaut:解码多态数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40751321/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com