递归案例类播放json lazyRead

时间:2018-02-27 11:02:45

标签: json scala deserialization playback recursive-datastructures

JsPath.scala中,lazyRead方法的说明如下:

/*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":[]}]}

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

( __ \ 'user).lazyRead(UserReads)

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

2 个答案:

答案 0 :(得分:0)

如@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()) }

答案 1 :(得分:0)

如果你没有选择JSON解析器,那么试试jsoniter-scala - 它内置支持递归结构和许多其他好东西,比如the best performance characteristics comparing to other JSON parsers for Scala