xmar
xmar

Reputation: 1809

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:

Upvotes: 1

Views: 1037

Answers (2)

CPS
CPS

Reputation: 537

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"...})

Upvotes: 1

Knows Not Much
Knows Not Much

Reputation: 31526

Spray Json doesn't support default parameters. So You cannot have a case class like

case class MyClass(a: String, b: Int = 0) 

and then parse json like {"a":"foo"}

However if you make the second parameter as Option. then it works.

  import spray.json._
  case class MyClass(a: String, b: Option[Int] = None)
  object MyProtocol extends DefaultJsonProtocol {
  implicit val f = jsonFormat2(MyClass)
  }
  import MyProtocol.f
  val mc1 = MyClass("foo", Some(10))
  val strJson = mc1.toJson.toString
  val strJson2 = """{"a": "foo"}"""
  val mc2 = strJson2.parseJson.convertTo[MyClass]
  println(mc2)

Upvotes: 1

Related Questions