【问题标题】:scala play reads parse nested jsonscala play读取解析嵌套的json
【发布时间】:2016-07-12 04:56:32
【问题描述】:

我正在使用implicit val reads 来映射 Json,例如:

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

到一个案例类

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

我只能使它与反映 JSON friends 结构的中间类一起工作。但我从不在我的应用程序中使用它。有没有办法编写一个 Reads[Response] 对象,以便我的 Response 类直接映射到给定的 JSON?

【问题讨论】:

  • 类似case class Response(id: Long, friends: Seq[Friend])?
  • 这会起作用,但我没有也不想创建Friend 类。我只需要他们的身份证

标签: json scala playframework playframework-2.0 playframework-json


【解决方案1】:

对于friend_ids,您只需要带有显式Reads.seq() 的简单Reads[Response],例如

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 重新编辑的答案链接

    所以,我想进一步了解如何将 json 解析为模型,并决定在 Reedit 上提问。收到了一些很酷的链接,看看:

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

    【讨论】:

      【解决方案3】:

      你可以试试下面的

      @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)。我想没有。
      猜你喜欢
      • 1970-01-01
      • 2018-10-06
      • 1970-01-01
      • 1970-01-01
      • 2021-05-13
      • 2018-10-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多