如何在反序列化以下案例类之前有条件地解析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
模型中成为可选字段?
答案 0 :(得分:3)
为避免将模型更改为可选字段,我们可以定义沿海岸航行的transformer,这样可以过滤掉缺少日期的用户,如
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)
答案 1 :(得分:1)
您可以使用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
的情况下可以使用。