1

我有两个案例类:

第一的:

object Person {
  implicit val jsonFormat = Json.format[Person]
}

case class Person(name: String, coWorkers: List[CoWorker])

一个人可能有 0 个或一些同事

第二:

object CoWorker {
  implicit val jsonFormat: Format[CoWorker] = Json.format[CoWorker]
}

case class CoWorker(position: String, person: Person)

我做了测试:

import org.specs2.mutable.Specification
import play.api.libs.json.{JsError, JsArray, Json}

class NestedSpec extends Specification {

  "Nested" should {

    "jsonReads" in {

      val personJson = Json.obj(
        "name" -> "alex",
        "coWorkers" -> Json.arr(
          Json.obj(
            "person" -> Json.obj(
              "name" -> "jack",
              "coWorkers" -> List.empty[String]
            ),
            "position": "developer" 
          )
        )
      )

      val res = personJson.validate[Person].asEither

      res.left.map(err => println(Json.prettyPrint(JsError.toJson(err))))

      res.isRight must beTrue

    }

  }

}

但是该测试失败并出现错误:

> testOnly  nested.NestedSpec
[info] NestedSpec
[info] 
[info] Nested should
[error]   ! jsonReads
[error]    java.lang.NullPointerException: null (JsConstraints.scala:32)
[error] play.api.libs.json.PathReads$$anonfun$at$1$$anonfun$apply$2.apply(JsConstraints.scala:32)
[error] play.api.libs.json.PathReads$$anonfun$at$1$$anonfun$apply$2.apply(JsConstraints.scala:32)
[error] play.api.libs.json.JsResult$class.flatMap(JsResult.scala:99)
[error] play.api.libs.json.JsSuccess.flatMap(JsResult.scala:9)
[error] play.api.libs.json.PathReads$$anonfun$at$1.apply(JsConstraints.scala:32)
[error] play.api.libs.json.PathReads$$anonfun$at$1.apply(JsConstraints.scala:32)
[error] play.api.libs.json.Reads$$anon$8.reads(Reads.scala:126)
[error] play.api.libs.json.OFormat$$anon$2.reads(Format.scala:46)
[error] play.api.libs.json.Reads$$anon$3$$anon$4.reads(Reads.scala:104)
[error] play.api.libs.json.OFormat$$anon$2.reads(Format.scala:46)
[error] play.api.libs.json.OFormat$$anon$5$$anonfun$inmap$1.apply(Format.scala:31)
[error] play.api.libs.json.OFormat$$anon$5$$anonfun$inmap$1.apply(Format.scala:31)
[error] play.api.libs.json.OFormat$$anon$1.reads(Format.scala:39)
[error] play.api.libs.json.Json$.fromJson(Json.scala:125)
[error] play.api.libs.json.LowPriorityDefaultReads$$anon$2$$anonfun$reads$1.apply(Reads.scala:168)
[error] play.api.libs.json.LowPriorityDefaultReads$$anon$2$$anonfun$reads$1.apply(Reads.scala:167)
[error] play.api.libs.json.LowPriorityDefaultReads$$anon$2.reads(Reads.scala:167)
[error] play.api.libs.json.DefaultFormat$$anon$4.reads(Format.scala:82)
[error] play.api.libs.json.PathReads$$anonfun$at$1$$anonfun$apply$2.apply(JsConstraints.scala:32)
[error] play.api.libs.json.PathReads$$anonfun$at$1$$anonfun$apply$2.apply(JsConstraints.scala:32)
[error] play.api.libs.json.JsResult$class.flatMap(JsResult.scala:99)
[error] play.api.libs.json.JsSuccess.flatMap(JsResult.scala:9)
[error] play.api.libs.json.PathReads$$anonfun$at$1.apply(JsConstraints.scala:32)
[error] play.api.libs.json.PathReads$$anonfun$at$1.apply(JsConstraints.scala:32)
[error] play.api.libs.json.Reads$$anon$8.reads(Reads.scala:126)
[error] play.api.libs.json.OFormat$$anon$2.reads(Format.scala:46)
[error] play.api.libs.json.Reads$$anon$3$$anon$4.reads(Reads.scala:104)
[error] play.api.libs.json.OFormat$$anon$2.reads(Format.scala:46)
[error] play.api.libs.json.OFormat$$anon$5$$anonfun$inmap$1.apply(Format.scala:31)
[error] play.api.libs.json.OFormat$$anon$5$$anonfun$inmap$1.apply(Format.scala:31)
[error] play.api.libs.json.OFormat$$anon$1.reads(Format.scala:39)
[error] play.api.libs.json.JsValue$class.validate(JsValue.scala:18)
[error] play.api.libs.json.JsObject.validate(JsValue.scala:76)
[error] nested.NestedSpec$$anonfun$1$$anonfun$apply$2.apply(NestedSpec.scala:24)
[error] nested.NestedSpec$$anonfun$1$$anonfun$apply$2.apply(NestedSpec.scala:10)
[info] 
[info] 
[info] 
[info] Total for specification NestedSpec
[info] Finished in 269 ms
[info] 1 example, 0 failure, 1 error
[info] 
[error] Error: Total 1, Failed 0, Errors 1, Passed 0
[error] Error during tests:
[error]         nested.NestedSpec
[error] (test:testOnly) sbt.TestsFailedException: Tests unsuccessful
[error] Total time: 1 s, completed May 18, 2016 12:25:16 PM

我想这是一种课程依赖错误。CoWorker 使用 Person 的 jsonReads,而 Person 使用 CoWorker jsonReads。是否可以解决此问题并进行测试?

4

1 回答 1

4

我需要使用在文档中找到的lazyReads:

递归类型 我们的示例模型没有演示的一种特殊情况是如何处理递归类型的读取和写入。JsPath 提供了lazyRead 和lazyWrite 方法,它们采用按名称调用的参数来处理这个问题:

case class User(name: String, friends: Seq[User])

implicit lazy val userReads: Reads[User] = (
  (__ \ "name").read[String] and
  (__ \ "friends").lazyRead(Reads.seq[User](userReads))
)(User)

implicit lazy val userWrites: Writes[User] = (
  (__ \ "name").write[String] and
  (__ \ "friends").lazyWrite(Writes.seq[User](userWrites))
)(unlift(User.unapply))

https://www.playframework.com/documentation/2.5.x/ScalaJsonCombinators#recursive-types

于 2016-05-18T10:00:53.147 回答