Due to the 22 field limit I had to split a large case class into smaller classes. How can I flatten the Writes
of this large class?
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
}
*/
}
Short story, you can do this :
implicit val writes: Writes[A] = JsPath.write[B].and(JsPath.write[C]) (unlift(A.unapply _))
Long story: Why are you able to use and
method ?
and
is available for any class that implements the typeclass FunctionalCanBuild
. What I noticed so far is that there is no such typeclass for Writes
, however there is one for OWrites
.
Using JsPath.write[B]
yields a OWrites
value, therefore and
method is available. On the other hand, using Writes.of[]
yields a Writes
, and OWrites.of[]
yields a Writes[]
. In the end, any method to get a OWrites[]
will allow you to use the key word and.
Also, looking further into the code, any instance of Applicative
typeclass is translatable to an instance of FunctionalCanBuild
. This typeclass is implemented for any Reads
hence the available and
method on the Readers.