Trying to run Json Combinator examples for Json Reads and Writes from http://www.playframework.com/documentation/2.2.x/ScalaJsonCombinators :
def test = Action {
case class Creature(name: String,isDead: Boolean,weight: Float, email: String, favorites: (String, Int), friends: List[Creature] = Nil, social: Option[String] = None)
import play.api.libs.json._
import play.api.libs.functional.syntax._
implicit val creatureWrites: Writes[Creature] = (
(__ \ "name").write[String] and
(__ \ "isDead").write[Boolean] and
(__ \ "weight").write[Float] and
(__ \ "email").write[String] and
(__ \ "favorites").write(
(__ \ "string").write[String] and
(__ \ "number").write[Int]
tupled
) and
(__ \ "friends").lazyWrite(Writes.traversableWrites[Creature](creatureWrites)) and
(__ \ "social").write[Option[String]]
)(unlift(Creature.unapply))
val gizmo = Creature("gremlins", false, 1.0F, "gizmo@midnight.com", ("alpha", 85), List(), Some("@gizmo"))
val gizmojs = Json.toJson(gizmo)
Ok(gizmojs toString)
}
I receive the following compile error:
[error] ....:forward reference extends over definition of value creatureWrites
[error] (__ \ "friends").lazyWrite(Writes.traversableWrites[Creature](creatureWrites))
I have a similar problem with Reads
and Format
.
Please help.
That's because you are define the implicit value as local member . Classes and objects allow forward references, whereas local block do not
So just define the implicit reads and writes as class member , not local
Look at my test
The Spec:
import play.api.libs.json._
import play.api.libs.functional.syntax._
import org.specs2.mutable.Specification
case class Creature(
name: String,
isDead: Boolean,
weight: Float,
email: String,
favorites: (String, Int),
friends: List[Creature] = Nil,
social: Option[String] = None)
class FooSpec extends Specification {
implicit val creatureWrites: Writes[Creature] = (
(__ \ "name").write[String] and
(__ \ "isDead").write[Boolean] and
(__ \ "weight").write[Float] and
(__ \ "email").write[String] and
(__ \ "favorites").write(
(__ \ "string").write[String] and
(__ \ "number").write[Int]
tupled
) and
(__ \ "friends").lazyWrite(Writes.traversableWrites[Creature](creatureWrites)) and
(__ \ "social").write[Option[String]]
)(unlift(Creature.unapply))
implicit val favouriteReads: Reads[(String, Int)] =
(__ \ "string").read[String]and
(__ \ "number").read[Int] tupled
implicit val creatureReads = Json.reads[Creature]
val gizmo = Creature("gremlins", false, 1.0F, "gizmo@midnight.com", ("alpha", 85), List(), Some("@gizmo"))
val gizmojs = Json.toJson(gizmo)
"writes" should {
"write scala value as string" in {
Json.parse(gizmojs.toString).as[Creature] must be_==(gizmo)
}
}
}
Result:
[success] Total time: 10 s, completed Jan 1, 2014 11:25:25 PM
[ops-ui] $ testOnly FooSpec
[info] FooSpec
[info] writes should
[info] + write scala value as string
[info] Total for specification FooSpec
[info] Finished in 1 second, 813 ms
[info] 1 example, 0 failure, 0 error
[info] Passed: Total 1, Failed 0, Errors 0, Passed 1
[success] Total time: 6 s, completed Jan 1, 2014 11:25:45 PM
You could define reads/writes easily like
implicit val favouriteWrites =
(__ \ "string").write[String] and
(__ \ "number").write[Int] tupled
implicit val creatureWrites: Writes[Creature] = Json.writes[Creature]
implicit val favouriteReads: Reads[(String, Int)] =
(__ \ "string").read[String]and
(__ \ "number").read[Int] tupled
implicit val creatureReads = Json.reads[Creature]
You're completely right, it doesn't work as documented. I think Play's JSON Combinators are still in a state of flux so the documentation is probably suffering as a result.
Quick fix: change creatureWrites
to be a def
, and thus the "forward reference" is allowed (it's a recursive function call):
implicit def creatureWrites: Writes[Creature] = (
...
)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.