创建递归 JSON 没有组合器模式的写入

Create recursive JSON Writes without combinator pattern

使用 JSON 组合器时,可以使用 lazyWrite 创建递归结构,如 documentation:

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

是否可以在实现写入的同时做到这一点,即:

implicit lazy val userWrites: Writes[User] = new Writes[User]{
    def writes(user: User) = Json.obj(
        "name" -> user.name,
        "friends" -> ??????
    )
}

是的。其实很简单。

implicit lazy val userWrites: Writes[User] = new Writes[User] {
    def writes(user: User) = Json.obj(
        "name" -> user.name,
        "friends" -> user.friends
    )
}


val joe = User("Joe", Nil)
val bob = User("Bob", Nil)
val jane = User("Jane", Seq(bob, joe))
val james = User("James", Seq(bob, jane))

scala> Json.toJson(james)
res0: play.api.libs.json.JsValue = {"name":"James","friends":[{"name":"Bob","friends":[]},{"name":"Jane","friends":[{"name":"Bob","friends":[]},{"name":"Joe","friends":[]}]}]}

userWrites其实也不需要偷懒。它像这样工作得很好,因为组合器试图通过隐式解析子写入并在树下工作来生成写入,这就是为什么它需要 lazyWrite 来阻止它在递归结构中无限下降。当写入 def writes 时,我们明确说明了写入的内容。

但是,这两种方法都不能使您免于这种情况:

def jim: User = User("Joe", Seq(dwight))
def dwight: User = User("Bob", Seq(jim))