【问题标题】:Convert json array to Seq of model class in Scala Play framework在Scala Play框架中将json数组转换为模型类的Seq
【发布时间】:2015-08-27 12:24:34
【问题描述】:

我正在使用 Scala Play 框架和 Instagram API,我想将一个 json 数组提取到我的模型类 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 对象映射到模型类,但是如何将 json 数组映射到用户的 Seq/List/Array?

【问题讨论】:

    标签: json scala playframework playframework-2.0


    【解决方案1】:

    Json 初始代码非常棒,它是我反序列化 json 的首选方式。您将不得不修改您的用户类以适应 instagram 模型 API。或者,如果您认为这对您的流程更好,您可以创建一个类似 InstagramApiUser 的案例类或进行反序列化并稍后复制到您自己的类中。这是代码,它在 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失败的原因。

    如果您不喜欢命名您的案例类成员以匹配 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 _)
    }
    

    除此之外,它的工作方式相同。

    【讨论】:

    • 太好了!但是没有办法避免字段名称与json名称匹配吗? profile_picture 有点“丑陋”……
    • 我的解决方案是添加更好的 getter 方法,例如:def name: String = full_namedef profilePhoto: String = profile_picture
    • 我同意。我也不想在我的 User 对象的类成员名称中使用下划线。我倾向于制作单个用例类来解析 API 数据,然后将数据移动到“更漂亮”的模型案例类。但是,如果您不想这样做,您也可以手动编写 Json Reads。我将编辑我的答案以显示一个示例。
    • 如何使用可选的 json 字段来实现这一点?在获取有关媒体的信息时,我想要JsPath \ "caption" \ "text",但有时标题只是空...
    • 4get,刚刚在stackoverflow.com/questions/14207942/…找到了解决方案
    【解决方案2】:

    我找到的解决方案如下:

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

    它可能存在一种更漂亮的方法,但我会坚持使用这种方法,直到其他答案为止。

    【讨论】:

    • 我在 scala case 类的属性之一中有 Long 类型。但是当我将 json 转换为该类的 seq 时,它给了我“erro.expected.long”
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-20
    • 1970-01-01
    • 2014-01-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多