在反序列化为案例类模型之前对 JSON 进行条件筛选



如何在反序列化为以下案例类之前有条件地解析 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 服务会返回一个没有startDateendDate的 JSON,例如:

{
"users":[
{
"id":"123",
"startDate":"2019-06-07",
"endDate":"2019-06-17"
},
{
"id":"333",
"startDate":"2019-06-07"
},
{
"id":"444"
}
]
}

如何有条件地解析 json 以忽略没有startDateendDate的对象,而不使这些字段在模型中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"
}
]
}

这意味着我们可以反序列化为现有模型,而无需将startDateendDate设置为可选。

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 _)
} 

当未提供startDateendDate时,这将起作用。

最新更新