如何在反序列化为以下案例类之前有条件地解析 JSON:
case class UserInfo(id: String, startDate: String, endDate: String)
我有一个隐含的阅读
object UserInfo {
implicit val reads: Reads[UserInfo] = (
(__ "id").read[String] and
(__ "startDate").read[String] and
(__ "endDate").read[String]
)(UserInfo.apply _)
}
我可以使用上面的隐式读取解析以下 json
val jsonString = """
{
"users":[
{
"id":"123",
"startDate":"2019-06-07",
"endDate":"2019-06-17"
},
{
"id":"333",
"startDate":"2019-06-07",
"endDate":"2019-06-27"
}
]
}"""
val userInfoList = (Json.parse(jsonString) "users").as[List[UserInfo]]
但有时 Web 服务会返回一个没有startDate
和endDate
的 JSON,例如:
{
"users":[
{
"id":"123",
"startDate":"2019-06-07",
"endDate":"2019-06-17"
},
{
"id":"333",
"startDate":"2019-06-07"
},
{
"id":"444"
}
]
}
如何有条件地解析 json 以忽略没有startDate
或endDate
的对象,而不使这些字段在模型中UserInfo
可选?
为了避免将模型更改为可选字段,我们可以定义海岸到海岸变压器,以过滤掉缺少日期的用户,例如
val filterUsersWithMissingDatesTransformer = (__ 'users).json.update(__.read[JsArray].map {
case JsArray(values) => JsArray(values.filter { user =>
val startDateOpt = (user "startDate").asOpt[String]
val endDateOpt = (user "endDate").asOpt[String]
startDateOpt.isDefined && endDateOpt.isDefined
})
})
其中给了
val jsonString =
"""
|{
| "users":[
| {
| "id":"123",
| "startDate":"2019-06-07",
| "endDate":"2019-06-17"
| },
| {
| "id":"333",
| "startDate":"2019-06-07"
| },
| {
| "id":"444"
| }
| ]
|}
""".stripMargin
val filteredUsers = Json.parse(jsonString).transform(filterUsersWithMissingDatesTransformer)
println(filteredUsers.get)
输出
{
"users": [
{
"id": "123",
"startDate": "2019-06-07",
"endDate": "2019-06-17"
}
]
}
这意味着我们可以反序列化为现有模型,而无需将startDate
和endDate
设置为可选。
case class UserInfo(id: String, startDate: String, endDate: String)
您可以使用Option
case class UserInfo(id: String, startDate: Option[String], endDate: Option[String])
object UserInfo {
implicit val reads: Reads[UserInfo] = (
(__ "id").read[String] and
(__ "startDate").readNullable[String] and
(__ "endDate").readNullable[String]
)(UserInfo.apply _)
}
当未提供startDate
和endDate
时,这将起作用。