用 Play 压平写入 Json

Flatten Writes with Play Json

由于 22 个字段的限制,我不得不将一个大案例 class 拆分为较小的 class。我怎样才能把这么大的class的Writes弄平?

import play.api.libs.json._
import play.api.libs.functional.syntax._

case class B(x: Option[Int], y: Option[Int])

object B {
  implicit val format: (Reads[B], Writes[B]) => Format[B] = Format[B]
}

case class C(z: Option[Int], w: Option[Int])

object C {
  implicit val format: (Reads[C], Writes[C]) => Format[C] = Format[C]
}

case class A(b: B, c: C)

object A {
  implicit val reads: Reads[A] =
    (Reads.of[B] and Reads.of[C]) (A.apply _)

  implicit val writes: Writes[A] = ???
  /*
  val a = A(B(1, 2), C(3, 4)

  Json.toJson(a) should be

  {
    "x": 1
    "y": 2
    "z": 3
    "w": 4
  }
   */
}

短篇小说,你可以这样做:

implicit val writes: Writes[A] = JsPath.write[B].and(JsPath.write[C]) (unlift(A.unapply _))

长话短说:为什么你可以使用 and 方法?

and 可用于任何实现类型 class FunctionalCanBuild 的 class。到目前为止,我注意到 Writes 没有这样的类型 class,但是 OWrites 有一个。

使用JsPath.write[B] 产生OWrites 值,因此and 方法可用。另一方面,使用 Writes.of[] 会产生 Writes,而 OWrites.of[] 会产生 Writes[]。最后,任何获得 OWrites[] 的方法都将允许您使用关键字 and.

此外,进一步查看代码,Applicative 类型 class 的任何实例都可以转换为 FunctionalCanBuild 的实例。此类型 class 为任何 Reads 实现,因此 Readers.

上可用的 and 方法