Search code examples
jsonscalasprayspray-json

Configure spray-json for non strict parsing deserialization


How to configure the spray-json parsing on parsing options? Similarly as Jackson Parsing Features.

For example, I am parsing a json that has a field that my case class has not, and it is breaking:

spray.json.DeserializationException: Object is missing required member 'myfield'

UPDATE :

A simple example:

case class MyClass(a: String, b: Long);

and try to parse an incomplete json like

val data = "{a: \"hi\"}"

with a spray-json format like:

jsonFormat2(MyClass.apply)
// ...
data.parseJson.convertTo[MyClass]

(simplified code).

But the question goes further, I want to ask about configuration options like in other parsers. More examples:

  • Be able to ignore fields that exist in the JSON but not in the case class.
  • Ways of managing nulls or nonexistent values. etc.

Solution

  • SprayJson allows you to define custom parsers like so:

    case class Foo(a: String, b: Int)
    implicit object FooJsonFormat extends RootJsonFormat[Foo] {
      override def read(json: JsValue): Foo = {
        json.asJsObject.getFields("name", "id") match {
          case Seq(JsString(name), id) =>
            Foo(name, id.convertTo[Int])
        }
      }
    
      override def write(obj: Foo): JsValue = obj.toJson
    }
    

    This allows you to parse any arbitrary payload and pull out the fields "name" and "id" - other fields are ignored. If those fields are not guaranteed you can add something like:

          case Seq(JsString(name), JsNull) =>
            Foo(name, 0)
    

    You should look at what's available in JsValue.scala - in particular JsArray may come in handy if you're getting payloads with anonymous arrays (i.e. the root is [{...}] instead of {"field":"value"...})