4

I have scala class like class A(b:Seq[String])

My problem is when I deserialize it from text which have no b field my class contains null. It is possible to force deserealizer to fill with empty Seq?

I use com.fasterxml.jackson.databind.ObjectMapper with com.fasterxml.jackson.module.scala.DefaultScalaModule.

EDIT: I want solution that fix all such fields without explicitly mentioning full list of them. Ir changing all declarations.

2
  • Are you open to using alternative JSON libraries? Commented Oct 5, 2015 at 18:07
  • Yes. I can use alternative library. Commented Oct 6, 2015 at 11:20

3 Answers 3

5
+50

This is not currently supported by Jackson, unfortunately.

You can see the relevant GitHub ticket here: https://github.com/FasterXML/jackson-databind/issues/347

Your best bet is to map null into an empty Seq in the class constructor or in an accessor method:

class A(_b: Seq[String]) {
  val b = _b match {
    case null => Nil
    case bs => bs
  }
}

(See also https://stackoverflow.com/a/20655330/8261 for other options)

Sign up to request clarification or add additional context in comments.

1 Comment

This solution require to make changes for each field of type Seg[?]. I want to fix problem in one place.
1

If you use Spray JSON, then a simple example which doesn't handle the absence of the b field would look like:

import spray.json._

case class A(b: Seq[String])

object Protocol extends DefaultJsonProtocol {
  implicit def aFormat = jsonFormat1(A)
}

import Protocol._

val str1 = """{ "b" : [] }""""
val str2 = """{ "b" : ["a", "b", "c"] }""""
val str3 = """{}"""
str1.parseJson.convertTo[A]//successful
str2.parseJson.convertTo[A]//successful
str3.parseJson.convertTo[A]//Deserialization error

In Spray JSON, this can be solved by writing a more detailed protocol format for class A:

import spray.json._

case class A(b: Seq[String])

object Protocol extends DefaultJsonProtocol {

  implicit object aFormat extends RootJsonFormat[A] {
    override def write(obj: A): JsValue = JsObject("b" -> obj.b.toJson)

    override def read(json: JsValue): A = json match {
      //Case where the object has exactly one member, 'b'
      case JsObject(map) if map.contains("b") && map.size == 1 => A(map("b").convertTo[Seq[String]])
      //Case where the object has no members
      case JsObject(map) if map.isEmpty => A(Seq())
      //Any other json value, which cannot be converted to an instance of A
      case _ => deserializationError("Malformed")
    }
  }
}

import Protocol._

val str1 = """{ "b" : [] }""""
val str2 = """{ "b" : ["a", "b", "c"] }""""
val str3 = """{}"""
str1.parseJson.convertTo[A]//successful
str2.parseJson.convertTo[A]//successful
str3.parseJson.convertTo[A]//successful

12 Comments

This solution requires explicitly specify all fields of Seq[?] type. I have lot of them and want all of them behave this way.
Can you give a concrete example? Is it many case classes or one class with many members of type seq?
Both of it. I have several case classes with multiple Seq field in each.
What if I have case class A(b: Seq[String]) and case class B(c: Seq[String]) and I am trying to deserialize { } how would I know which case class to target?
I don't know how jackson handle this situation, but how it relates to my question? Same problem appear even without Seq field
|
0

I had a similar problem deserializing String arrays with jackson, and found that jackson apparently (have not tried yet) fixed this in jackson-module 2.1.2. It might work for Seq. https://github.com/FasterXML/jackson-module-scala/issues/48

1 Comment

We use jackson-module-scala_2.11 version 2.6.1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.