我有一个包含事件数组的 JSON 结构。该数组是“多态的”,因为存在三种可能的事件类型A
,B
并且C
:
{
...
"events": [
{ "eventType": "A", ...},
{ "eventType": "B", ...},
{ "eventType": "C", ...},
...
]
}
这三种事件类型没有相同的对象结构,所以我需要不同Reads
的。除此之外,整个 JSON 文档的目标案例类区分事件:
case class Doc(
...,
aEvents: Seq[EventA],
bEvents: Seq[EventB],
cEvents: Seq[EventC],
...
)
如何定义内部结构,Reads[Doc]
以便将 json 数组events
拆分为三个子集,这些子集映射到aEvents
和?bEvents
cEvents
到目前为止我尝试过的(没有成功):
首先,我定义了 aReads[JsArray]
将原始转换为仅包含特定类型事件的JsArray
另一个:JsArray
def eventReads(eventTypeName: String) = new Reads[JsArray] {
override def reads(json: JsValue): JsResult[JsArray] = json match {
case JsArray(seq) =>
val filtered = seq.filter { jsVal =>
(jsVal \ "eventType").asOpt[String].contains(eventTypeName)
}
JsSuccess(JsArray(filtered))
case _ => JsError("Must be an array")
}
}
然后的想法是像这样在内部使用它Reads[Doc]
:
implicit val docReads: Reads[Doc] = (
...
(__ \ "events").read[JsArray](eventReads("A")).andThen... and
(__ \ "events").read[JsArray](eventReads("B")).andThen... and
(__ \ "events").read[JsArray](eventReads("C")).andThen... and
...
)(Doc.apply _)
但是,我不知道如何从这里继续下去。我假设该andThen
部分应该看起来像这样(在事件 a 的情况下):
.andThen[Seq[EventA]](EventA.reads)
但这不起作用,因为我希望 APISeq[EventA]
通过显式传递 aReads[EventA]
而不是Reads[Seq[EventA]]
. 除此之外,由于我从未运行过它,所以我不确定整个方法一开始是否合理。
编辑:如果原始JsArray
包含未知的事件类型(例如D
和E
),这些类型应该被忽略并从最终结果中排除(而不是使整个Reads
失败)。