Search code examples
jsonscalaplay-json

JSON Objects null filtering in scala


I am using play.api.libs.json in Scala (2.12.8) to process some json objects. I have for example a JSON string that looks like:

{
  "field1": null,
  "field2": 23,
  "field3": {
    "subfield1": "a",
    "subfield2": null
  },
  "field4": {
    "subfield1": true,
    "subfield2": {
      "subsubfield1": null,
      "subsubfield2": "45"
    },
    "field5": 3
  }
}

And I want to filter out every null fields or subfields.

As explained here: Play: How to remove the fields without value from JSON and create a new JSON with them

Doing:

import play.api.libs.json.{ JsNull, JsObject, JsValue, Json }

val j = Json.parse(myJsonString).as[JsObject]
JsObject(j.fields.filterNot(t => withoutValue(t._2)))

def withoutValue(v: JsValue) = v match {
  case JsNull => true
  case _      => false
}

helps me remove the upper level fields: in my case, field1

But field3.subfield2 and field4.subfield2.subsubfield1 are still present. I want to remove them. Also I should mention that not every subfields can be null at once. Should this happen, I think we could just remove the upper level field. If field3.subfield1and field3.subfield2 are null, we can remove field3.

Any idea on how to do this neatly in Scala?

PS: the desired output is:

{
  "field2": 23,
  "field3": {
    "subfield1": "a"
  },
  "field4": {
    "subfield1": true,
    "subfield2": {
      "subsubfield2": "45"
    },
    "field5": 3
  }
}

Solution

  • You need to do a recursive solution. For example:

    def removeNulls(jsObject: JsObject): JsValue = {
      JsObject(jsObject.fields.collect {
        case (s, j: JsObject) =>
          (s, removeNulls(j))
        case other if (other._2 != JsNull) =>
          other
      })
    }
    

    Code run at Scastie. Output is as expected.