在 Scala Play 框架中将 json 数组转换为模型 class 的 Seq

Convert json array to Seq of model class in Scala Play framework

我正在使用 Scala Play 框架和 Instagram API,我想提取一个 json 数组到我的模型 class User:

case class User(val userId: String, val username: String, val profilePhoto: String, val name: String)

来自 API 的 json 数组示例是这样的:

{
  "pagination":  {},
  "meta":  {},
  "data":  [
     {
      "username": "carolinabentocb",
      "profile_picture": "https://igcdn-photos-f-a.akamaihd.net/hphotos-ak-xfa1/t51.2885-19/s150x150/11429783_1673078532912085_1496721162_a.jpg",
      "id": "363753337",
      "full_name": "Carolina Bento"
    },
     {
      "username": "pereira3044",
      "profile_picture": "https://igcdn-photos-e-a.akamaihd.net/hphotos-ak-xaf1/t51.2885-19/s150x150/11351764_1662987433917180_971708049_a.jpg",
      "id": "2141448590",
      "full_name": "Alex"
    }
]
}

this link 中解释了如何将 json 对象映射到模型 class,但是如何将 json 数组映射到 Seq/List/Array 用户?

我找到的解决方案如下:

val users: Seq[User] = (json \ "data").as[JsArray].value.map(j => j.validate[User].get)

可能存在更漂亮的方法,但在其他答案之前我会坚持使用这个方法。

Json 初始代码非常棒,它是我反序列化 json 的首选方式。您将必须修改您的用户 class 以适应 instagram 模型 API。或者,您可以制作一个 class 之类的 InstagramApiUser 或其他东西来进行反序列化,如果您认为这对您的流程更好,则稍后复制到您自己的 class 。这是代码,它在 scala repl 中工作。

import play.api.libs.json.{Json, Format}


val js = Json.parse("""{
  "pagination":  {},
  "meta":  {},
  "data":  [
     {
      "username": "carolinabentocb",
      "profile_picture": "https://igcdn-photos-f-a.akamaihd.net/hphotos-ak-xfa1/t51.2885-19/s150x150/11429783_1673078532912085_1496721162_a.jpg",
      "id": "363753337",
      "full_name": "Carolina Bento"
    },
     {
      "username": "pereira3044",
      "profile_picture": "https://igcdn-photos-e-a.akamaihd.net/hphotos-ak-xaf1/t51.2885-19/s150x150/11351764_1662987433917180_971708049_a.jpg",
      "id": "2141448590",
      "full_name": "Alex"
    }
  ]
}""")

case class User(id: String, username: String, profile_picture: String, full_name: String)
object User {
  implicit val jsonFormat: Format[User] = Json.format[User]
}

val result = (js \ "data").as[Seq[User]]

Play Json 库中有三种反序列化 Json 的方法,as 是我认为最不惯用的方法,因为它在解析失败时抛出异常.您可以尝试使用 asOpt[A] 将产生 Option[A] 或更好的 validate[A] 将产生 JsResult[A] 然后您可以记录错误以及解析您的原因Json失败。

如果您不喜欢命名您的案例 class 成员以匹配 API 名称,您可以像

一样手动编写 Reads
import play.api.libs.json.{Json, Reads, JsPath}
import play.api.libs.functional.syntax._

case class User(val userId: String, val username: String, val profilePhoto: String, val name: String)
object User {
  implicit val jsonReads: Reads[User] = (
    (JsPath \ "id").read[String] and
    (JsPath \ "username").read[String] and 
    (JsPath \ "profile_picture").read[String] and
    (JsPath \ "full_name").read[String]
  )(User.apply _)
}

其他方面都是一样的。