3

I've been working to return JSON from a Scalatra application using the implicit conversions described in the docs.

I've noticed that keys with empty Options (ie, None) are stripped from the resulting JSON (as opposed to being null, which seems like the expected behaviour)

I have attempted to use implicit conversions to cast None to null, like:

class NoneJNullSerializer extends CustomSerializer[Option[_]](format => (
  {
    case JNull => None
  }, {
    case None => JNull
  }
  ))

protected implicit val jsonFormats: Formats = DefaultFormats.withBigDecimal + new NoneJNullSerializer()

however the keys seem to be stripped prior to execution of the custom serializers.

Has anyone found a solution to this?

Note that the solution described in this question works in the described case of arrays, however does not seem to work with Maps.

UPDATE: This is the test I have been using:

  get("/testJSON") {
    Map(
      "test_key" -> "testValue" ,

      "test_key6" -> "testValue6" ,
      "subObject" -> Map(
        "testNested1" -> "1" ,
        "testNested2" -> 2 ,
        "testArray" -> Seq(1, 2, 3, 4)
      ),
    "testNone" -> None ,
    "testNull" -> null ,
    "testSomeNull" -> Some(null) ,
    "testJNull" -> JNull ,
    "testSomeJNull" -> Some(JNull)
    )
  }

and the output I am looking for is

{
    "test_key": "testValue",
    "test_some_j_null": null,
    "sub_object": {
        "test_nested1": "1",
        "test_nested2": 2,
        "test_array": [
            1,
            2,
            3,
            4
        ]
    },
    "test_none": null,
    "test_j_null": null,
    "test_key6": "testValue6",
    "test_null": null,
    "test_some_null": null
}

I am also using

protected override def transformResponseBody(body: JValue): JValue = { body.underscoreKeys }

for underscored keys

Community
  • 1
  • 1
Nick Mitchinson
  • 5,452
  • 1
  • 25
  • 31

1 Answers1

0

Using a custom serializer should work also for maps.

import org.json4s._
import org.json4s.jackson.JsonMethods._

object testNull extends App {

  val data = Map(
    "testNone" -> None,
    "testNull" -> null,
    "testSomeNull" -> Some(null),
    "testJNull" -> JNull,
    "testSomeJNull" -> Some(JNull)
  )

  class NoneJNullSerializer extends CustomSerializer[Option[_]](format => ( {
    case JNull => None
  }, {
    case None => JNull
  }))

  implicit val formats = DefaultFormats + new NoneJNullSerializer

  val ast = Extraction.decompose(data)

  println(pretty(ast))

  //  {
  //    "testSomeJNull" : null,
  //    "testJNull" : null,
  //    "testNone" : null,
  //    "testNull" : null,
  //    "testSomeNull" : null
  //  }

}
Stefan Ollinger
  • 1,577
  • 9
  • 16