反序列化为案例类模型之前对JSON进行条件过滤

时间:2019-06-14 14:51:39

标签: json scala playframework play-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模型中成为可选字段?

2 个答案:

答案 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"
    }
  ]
}

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

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

在未提供startDateendDate的情况下可以使用。