我有两个案例类:
首先:
object Person {
implicit val jsonFormat = Json.format[Person]
}
case class Person(name: String, coWorkers: List[CoWorker])
人可能有0或某些CoWorkers
第二
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。有可能解决这个问题并让测试运行吗?
答案 0 :(得分:1)
我需要使用lazyReads,可以在docs中找到:
递归类型我们的示例模型没有的一种特殊情况 演示如何处理递归类型的读取和写入。 JsPath提供了call-by-name的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