简体   繁体   中英

JSON arrays and Scala Seq

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.

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)

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM