How to customize the JSON output depending on the value of a Option type in the case class?

Viewed 23

Say I have a case class like:

case class KVP(customKey: Option[String], value: String)

I can create a JSON writes method like:

implicit val kvpWrites: Writes[KVP] = (
    ( __ \ "customKey").write[Option[String]] and
    ( __ \ "value").write[String]

)(unlift(KVP.unapply))

So the JSON will look something like for KVP("location", "NY")

{
   "customKey": "location",
   "value": "NY"
}

But what I want is this, if customKey has a value I want:

{
    "location": "NY"
}

if customKey is a None, I want:

{
    "value": "NY"
}

How can I achieve this?

1 Answers

You can write a custom Writes like this:

implicit val kvpWrites: OWrites[KVP] = new OWrites[KVP] {
  def writes(kvp: KVP): JsObject = {
    // Build a JsValue by yourself
    Json.obj(Seq(kvp.customKey.getOrElse("value") -> kvp.value))
  }
}

Or simplified:

implicit val kvpWrites: OWrites[KVP] = OWrites[KVP] { (kvp: KVP) =>
  Json.obj(Seq(kvp.customKey.getOrElse("value") -> kvp.value))
}
Related