I have a big case class with 10+ fields, that represents a JSON payload, that comes from user. Most of fields are optional, so I'm using Option
in this cases (Option[String]
for string fields. And that is nice approach, until I need an optional sequence. I think that writing Option[Seq[String]] is weird, cause empty sequence is enough to show that there is no data (for any reason).
I could handle it in manual way, though:
implicit val reads = new Reads[MyCaseClass] {
def reads(js: JsValue): JsResult[MyCaseClass] = {
JsSuccess(MyCaseClass(
(js \ "unit_code").as[String],
// other fields omited
(js \ "positions").asOpt[Seq[String]] match {
case Some(seq: Seq[String]) => seq
case None => Seq.empty[String]
}
))
}
}
But I don't won't to write all this stuff manually. There could be mistakes, I need to test it separately, and, for sure, it takes much more time, rather than to write implicit val f = Json.format[MyCaseClass]
.
Is there any option to separately handle only one field, that other fields handling let on the default macro?
Thanks for user 'cchantep' to pointing to Json transformers. So that is how I solve the issue:
Case class:
case class MyCaseClass(unit_code: String, positions: Seq[String] = Seq.empty)
Companion object
object MyCaseClass {
private val readsTransformer: Reads[JsObject] = __.json.update(
__.read[JsObject]
.map{ o =>
if (o.keys.exists(p => p.equals("positions"))) {
o
} else {
o ++ Json.obj("positions" -> JsArray())
}
}
)
implicit val readsImplicit: Reads[MyCaseClass] = readsTransformer.andThen(Json.reads[MyCaseClass])
implicit val writesImplicit: OWrites[MyCaseClass] = Json.writes[MyCaseClass]
}
That looks a bit cumbersome, but it is possible to write common function that creates transformer for exact field, so in each companion object it wouldn't be so verbose.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With