У меня есть структура JSON, которая содержит массив событий. Массив «полиморфный» в том смысле, что существует три возможных типа событий A
, B
и C
:Воспроизведение JSON Reads [T]: разбить JsArray на несколько подмножеств
{
...
"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
?
То, что я пытался до сих пор (не будучи успешным):
Во-первых, я определил Reads[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
часть должна выглядеть примерно так (в случае событий а):
.andThen[Seq[EventA]](EventA.reads)
Но это не работает, так как я ожидаю, что API для создания Seq[EventA]
, явно передавая Reads[EventA]
вместо Reads[Seq[EventA]]
. И кроме того, поскольку я никогда не запускал его, я не уверен, что в целом этот подход разумный.
редактировать: в случае, если оригинал JsArray
содержит неизвестные типы событий (например, D
и E
), эти типы должны быть проигнорированы и исключены из окончательного результата (вместо того, чтобы весь Reads
неудачу).
Можете вы изменить структуру json? Что-то вроде '{ ... события: { : с [... события типа A], б: [... события типа B], с: [... события типа C] } } ' Это должно быть проще, чтобы преобразовать их обратно с помощью считываний, которые вы уже определили. – marceloemanoel
Другой способ. Преобразовать «события» JsArray в Tuple3 [Seq [EventA]], Seq [EventB]], Seq [EventC]], а затем отобразить результат в Doc. –