Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

I need advice on Play's Json and elegant Option handling in the Writes trait

I have a "style" or "effective scala" type of question here: I have a "FeatureCheck" class which I need to serialize into a Json in Play framework.

case class FeatureCheck(val result: Option[Boolean], val missing: Option[Array[String]], val error: Option[String])

I am serializing it using my own "writes" but my code looks a lot like Java code. I would like to serialize each option in the check object only if it is defined (the final object should not have any empty values).

def writes(check: FeatureCheck): JsValue = {
  val builder = Seq.newBuilder[(String, JsValue)]
  if (check.error.isDefined) {
    builder += "error" -> JsString(check.error.get)
  }
  if (check.missing.isDefined) {
    builder += "missing" -> Json.toJson(check.missing.get)
  }
  if (check.result.isDefined) {
    builder += "result" -> JsBoolean(check.result.get)
  }
  JsObject(builder.result)
}

So I was wondering if there was a way to do this without those ugly if-then, or even removing the builder for the sequence.

Thanks for any help or comment given.

Clarrifications:

Let's say I want to just send result = true I want the resulting Json to be:

{"result":true} 

and NOT

{
    "result": true,
    "error": null,
    "missing": []
}
like image 228
le-doude Avatar asked Apr 29 '13 11:04

le-doude


1 Answers

Given that you can simply append an option to a seq (see Add to list if value is not null), you can do what you want rather elegantly:

type JsField = (String, JsValue)
def writes(check: FeatureCheck): JsValue = {
  JsObject(
    Seq[JsField]() ++
    check.error.map("error" -> JsString(_)) ++
    check.missing.map("missing" -> Json.toJson(_)) ++
    check.result.map("result" -> JsBoolean(_))    
  )
}
like image 192
Régis Jean-Gilles Avatar answered Nov 09 '22 04:11

Régis Jean-Gilles