我有一个来自 API 响应的 json,如下所示:
[{
value: true(Boolean),
name: "xyz",
date: 11/12/2020
},
{
value: "abc"(String),
name: "djd",
date: 11/12/2020
}]
它基本上具有类似的结构,但其中一个属性(值)可能包含不同的数据类型。如何将此响应解析为类?我正在尝试这样做,但我不确定如何编写 MainData 类。 有什么想法吗?
trait Data[A] {
val value: A
val date: ZonedDateTime
val name: String
}
case class ClassA(
value: Boolean,
name: String,
date: ZonedDateTime
) extends Data[Boolean]
case class ClassB(
value: String,
name: String,
date: ZonedDateTime
) extends Data[String]
case class MainData(data: Seq[Data[A])
在响应处理程序中,如下所示:
case rsp if 200 == rsp.status =>
val response = rsp.body.as[MainData[A]]
您可以为ClassA
和ClassB
创建单独的Reads
实例,然后根据value
字段的类型使用适当的实例。大致如下:
val aReads = Json.reads[ClassA]
val bReads = Json.reads[ClassB]
implicit val dataReads = new Reads[Data[_]] {
def reads(json: JsValue) = (json "value") match {
case JsDefined(JsString(_)) => bReads.reads(json)
case JsDefined(JsBoolean(_)) => aReads.reads(json)
case x => JsError(s"Unknown data type: $x")
}
}
这样,您的json.as[Data[_]]
或json.as[MainData]
将拾取dataReads
进而调用正确的实例。 或者,您根本不需要使用单独的aReads
和bReads
读取器,并完全实现read(...)
方法:
implicit val dataReads = new Reads[Data[_]] {
def reads(json: JsValue) = {
val name = (json "name").as[String]
val date = (json "date").as[ZonedDateTime]
(json "value") match {
case JsDefined(JsString(str)) => JsSuccess(ClassB(str, name, date))
case JsDefined(JsBoolean(bln)) => JsSuccess(ClassA(bln, name, date))
case x => JsError(s"Unknown data type: $x")
}
}
}