【问题标题】:Recursive case class play json lazyRead递归案例类播放jsonlazyRead
【发布时间】:2018-02-27 11:02:44
【问题描述】:

JsPath.scalalazyRead方法的描述如下:

/*case class User(id: Long, name: String, friend: User)

implicit lazy val UserReads: Reads[User] = (
  (__ \ 'id).read[Long] and
  (__ \ 'name).read[String] and
  (__ \ 'friend).lazyRead(UserReads)
)(User.apply _) */ 

def lazyRead[T](r: => Reads[T]): Reads[T] = Reads(js => Reads.at[T]
(this)(r).reads(js)) 

当我尝试执行上述示例的简化版本时:

case class User(id:Int, user: User)

val userJsVal = Json.parse(
  """
    | {
    |   "id" : 22,
    |   "user" : { "id":2  }
    | }
  """.stripMargin)


implicit lazy val UserReads: Reads[User] = (
        (__ \ 'id).read[Int] and
         ( __ \ 'user).lazyRead(UserReads)
        )(User.apply _)

val us = Json.fromJson[User](userJsVal)(UserReads);
us match {
   case s:JsSuccess[User] => println(s.get)
   case e:JsError =>  println(JsError.toJson(e).toString()) }

我得到错误:

{"obj.user.user":[{"msg":["error.path.missing"],"args":[]}]}

我尝试将最里面的“用户”设置为 null,但这也不起作用。我应该如何构建我的 json 或添加终止条件:

( __ \ 'user).lazyRead(UserReads)

要获得有效的反序列化输出?

【问题讨论】:

  • 还尝试了代码 [gist.github.com/mandubian/6046786],它给出了以下错误:forward reference extends over definition of value treeReads [error] ( __ \ "l").lazyRead(treeReads) and [error] ^
  • 恕我直言 case class User(id: Int, user: Option[User]) 将是更安全的定义,以避免在运行时检查 null 和 NPE

标签: json scala deserialization playback recursive-datastructures


【解决方案1】:

正如@Andriy 所提到的,您的 User 对象必须有一个 Option[User] 否则您的内部对象将始终需要无限地拥有另一个用户。 您会注意到,在您的 JSON 示例中,内部用户下面已经没有其他用户了。 然后在您将内部用户更改为可选后,您应该使用lazyReadNullable,这是您修复的示例:

import play.api.libs.json.{JsError, JsSuccess, Json, Reads}
import play.api.libs.json._
import play.api.libs.functional.syntax._

case class User(id:Int, user: Option[User])

val userJsVal = Json.parse(
  """
    | {
    |   "id" : 22,
    |   "myuser" : { "id":2  }
    | }
  """.stripMargin)


implicit lazy val UserReads: Reads[User] = (
    (__ \ 'id).read[Int] and
    ( __ \ 'myuser).lazyReadNullable(UserReads)
  )(User.apply _)

val us = Json.fromJson[User](userJsVal)(UserReads)

us match {
  case s:JsSuccess[User] => println(s.get)
  case e:JsError =>  println(JsError.toJson(e).toString()) }

【讨论】:

    【解决方案2】:

    如果您对 JSON 解析器的选择没有限制,请尝试 jsoniter-scala - 它内置了对递归结构和许多其他好东西的支持,例如 the best performance characteristics comparing to other JSON parsers for Scala

    【讨论】:

      猜你喜欢
      • 2019-06-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-07
      相关资源
      最近更新 更多