イベントの配列を含む JSON 構造があります。A
この配列は、次の 3 つのイベント タイプが考えられるという意味で「多態的」B
ですC
。
{
...
"events": [
{ "eventType": "A", ...},
{ "eventType": "B", ...},
{ "eventType": "C", ...},
...
]
}
3 つのイベント タイプのオブジェクト構造は同じではないReads
ため、それぞれに異なるオブジェクト構造が必要です。それとは別に、JSON ドキュメント全体のターゲット ケース クラスは、イベントを区別します。
case class Doc(
...,
aEvents: Seq[EventA],
bEvents: Seq[EventB],
cEvents: Seq[EventC],
...
)
Reads[Doc]
の内部を定義して、json 配列が、およびevents
にマップされる 3 つのサブセットに分割されるようにするにはどうすればよいですか?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
ようになるはずです(イベントaの場合):
.andThen[Seq[EventA]](EventA.reads)
しかし、API が の代わりにaSeq[EventA]
を明示的に渡すことによってを作成することを期待しているため、それは機能しません。それとは別に、私はそれを実行したことがないので、そもそもこのアプローチ全体が合理的かどうかはわかりません.Reads[EventA]
Reads[Seq[EventA]]
編集:オリジナルJsArray
に不明なイベント タイプ (例:D
およびE
) が含まれている場合、これらのタイプは無視され、最終結果から除外されます (全体Reads
が失敗するのではなく)。