Scala Play 解析嵌套的 JSON

4
我将使用“隐式val reads”来映射Json,如下所示:

{
   "id": 1
   "friends": [
    {
      "id": 1,
      "since": ...
    },
    {
      "id": 2,
      "since": ...
    },
    {
      "id": 3,
      "since": ...
    }
  ]
}

转换为一个case类

case class Response(id: Long, friend_ids: Seq[Long])

我只能使用一个中间类来反映JSON friends 结构,才能让它正常工作。但我从未在我的应用程序中使用过它。有没有一种方法可以编写一个 Reads [Response] 对象,使我的 Response 类直接映射到给定的JSON?


类似于 case class Response(id: Long, friends: Seq[Friend]) 这样的东西吗? - mfirry
这个会起作用,但我没有也不想创建Friend类。我只需要他们的ID。 - roman-roman
3个回答

5

您只需要使用明确的Reads.seq()读取响应中的friend_ids,例如:

val r: Reads[Response] = (
  (__ \ "id").read[Long] and
    (__ \ "friends").read[Seq[Long]](Reads.seq((__ \ "id").read[Long]))
  )(Response.apply _)

而结果将会是:
r.reads(json)

scala> res2: play.api.libs.json.JsResult[Response] = JsSuccess(Response(1,List(1, 2, 3)),)

2

简单的方法可能是:

import play.api.libs.functional.syntax._
import play.api.libs.json.{JsValue, Json, _}


case class Response(id: Long, friend_ids: Seq[Friends])

object Response {

  implicit val userReads: Reads[Response] = (
    (JsPath \ "id").read[Long] and
      (JsPath \ "friends").read[Seq[Friends]]
    ) (Response.apply _)
}

case class Friends(id: Long, since: String)
object Friends {
  implicit val fmt = Json.format[Friends]
}

没有case class Friends,我发现很难找到解决方案,但如果我找到了一个,就会发布。

编辑:添加了在Scala Reedit上回答的链接

所以,我想更深入地了解如何将json解析为模型,并决定在Reedit上询问。收到一些非常酷的链接,看看:

https://www.reddit.com/r/scala/comments/4bz89a/how_to_correctly_parse_json_to_scala_case_class/


1
您可以尝试以下内容。
@annotation.tailrec
def go(json: Seq[JsValue], parsed: Seq[Long]): JsResult[Seq[Long]] =
  json.headOption match {
    case Some(o @ JsObject(_)) => (o \ "id").validate[Long] match {
      case JsError(cause) => JsError(cause)
      case JsSuccess(id)  => go(json.tail, parsed :+ id)
    }
    case Some(js) => JsError(s"invalid friend JSON (expected JsObject): $js")
    case _ => JsSuccess(parsed) // nothing more to read (success)
  }

implicit val friendIdReader = Reads[Seq[Long]] {
  case JsArray(values) => go(values, Nil)
  case json => JsError(s"unexpected JSON: $json")
}

implicit val responseReader = Json.reads[Response]
// responseReader will use friendIdReader as Reads[Seq[Long]],
// for the property friend_ids

谢谢您的建议!那可能会起作用,但如果没有更简单的方法,我宁愿使用实用程序类(例如Friend)。我想没有更简单的方法了。 - roman-roman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接