2016-05-18 9 views
0

ich zwei Fallklassen haben:Spiel json, rekursive liest, NPE

Erstens:

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

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

Person kann 0 oder einige Mitarbeiter

Zweitens:

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

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

I Test gemacht:

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 

    } 

    } 

} 

Aber das Test nicht mit Fehlern:

> 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 

Ich nehme an, dass es eine Art von curricularem Abhängigkeitsfehler ist. CoWorker verwendet Persons jsonReads und Person verwendet CoWorker jsonReads. Ist es möglich, dieses Problem zu lösen und den Test laufen zu lassen?

Antwort

0

Ich brauche lazyReads zu verwenden, in docs gefunden:

rekursive Typen Ein Sonderfall, dass unser Beispiel Modell nicht zeigen, wie Liest zu handhaben und schreibt für rekursive Typen. JsPath bietet lazyRead und lazywrite Methoden, die diese Parameter Call-by-name nehmen zu handhaben:

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