我有一个抽象类型PolyType
以及此类型的具体实现,TypeA
,TypeB
和TypeC
。目标是解析包含这三种类型的序列化表示的JSON数组。每个数组可以同时包含所有三种类型。
我正在使用以下Reads
进行反序列化:
implicit val polyReads = new Reads[PolyType] {
override def reads(json: JsValue): JsResult[PolyType] =
json.validate(
typeAReads.map(_.asInstanceOf[TypeA]) orElse
typeBReads.map(_.asInstanceOf[TypeB]) orElse
typeCReads.map(_.asInstanceOf[TypeC])
)
}
最终,我可以像这样使用它来解析包含这三种类型的JSON数组:
val json: JsValue = { ... }
val result = json.validate[Seq[PolyType]]
// => JsResult[Seq[PolyType]], Seq contains instances of A, B and C
这在概念上起作用。结果是Seq[PolyType]
,其中包含TypeA
,TypeB
和TypeC
的实例。请注意我不必手动处理Seq
,例如我不需要明确检查输入是否代表一个json数组(如果没有,我得到一个JsError
,这很好。)
但我真正想做的是:
首先,仅提取 TypeA
个实例。这是因为TypeA
包含正确解析TypeB
和TypeC
所需的定义。因此Reads
和TypeB
的{{1}}是“动态的”,需要TypeC
的具体实例。我没有为B和C定义那些“动态”TypeA
的问题。
但我想知道:
Reads
以及以后?TypeA
将无法工作,因为json数组还包含导致错误的其他两种类型。答案 0 :(得分:0)
我不知道TypeA
如何用于提取TypeB
和TypeC
,因此我只能告诉您如何提取TypeA
的所有实例。首先,一些示例类型:
导入play.api.libs.json ._
trait PolyType
case class TypeA(a: String) extends PolyType
case class TypeB(b: String) extends PolyType
case class TypeC(c: String) extends PolyType
implicit val typeAReads: Reads[TypeA] = Json.reads[TypeA]
implicit val typeBReads: Reads[TypeB] = Json.reads[TypeB]
implicit val typeCReads: Reads[TypeC] = Json.reads[TypeC]
示例数据:
val json = Json.parse("""
[
{"a": "Some A"},
{"b": "Some B"},
{"c": "Some C"},
{"c": "Other C"},
{"a": "Other A"},
{"b": "Other B"}
]
""")
然后,我定义Reads[Seq[TypeA]]
首先尝试将validate
JSON设为JsArray
,然后将validate
数组中的每个成员TypeA
定义为collect
,implicit val typeASeqReads = new Reads[Seq[TypeA]] {
def reads(js: JsValue): JsResult[Seq[TypeA]] = {
js.validate[JsArray].map { array =>
array.value.map(_.validate[TypeA])
.collect { case JsSuccess(a, _) => a }
}
}
}
只有那些成功的人。
scala> json.validate[Seq[TypeA]]
res0: play.api.libs.json.JsResult[Seq[TypeA]] = JsSuccess(ListBuffer(TypeA(Some A), TypeA(Other A)),)
结果:
JsSuccess
注意事项:
TypeA
。因此,如果没有有效的Seq
,则会返回空的TypeA
。Reads[Seq[PolyType]]
和其他类型,将非常困难。 最后,您需要一个特殊的UnsafePointer<Void>
来处理在列表中进行多次传递的要求。