当多态类型在Seq()内时,Jackson中使用Scala模块进行多态反序列化失败

时间:2013-08-12 11:53:07

标签: json scala polymorphism jackson

鉴于这个简单的例子,第三个测试“反序列化”失败并显示消息。

Can not construct instance of com.egc.ost.pricing.contracts.response.A, problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information
 at [Source: java.io.StringReader@1f03691; line: 2, column: 29]
com.fasterxml.jackson.databind.JsonMappingException: Can not construct instance of com.egc.ost.pricing.contracts.response.A, problem: abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information
 at [Source: java.io.StringReader@1f03691; line: 2, column: 29] 

即使第二个测试“de-serialize_a”证明Jackson可以解析正确的多态类型。

我正在使用Jackson版本和scala模块

  <dependency>
        <groupId>com.fasterxml.jackson.module</groupId>
        <artifactId>jackson-module-scala_2.10</artifactId>
        <version>2.2.2</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.datatype</groupId>
        <artifactId>jackson-datatype-joda</artifactId>
        <version>2.2.2</version>
    </dependency>

代码:

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXTERNAL_PROPERTY, property = "type")
@JsonSubTypes(Array(
  new Type(value = classOf[B], name = "B"),
  new Type(value = classOf[C], name = "C")))
trait A{}

case class B(value : Double) extends A
case class C(value : String) extends A

case class Owner( results: Seq[(String, A)])

class ATest extends FlatSpec with ShouldMatchers {
  behavior of "A"

  it should "serialise"  in {
    val owner : Owner = Owner(Seq(("ExampleB",B(1.0)),("ExampleC",C("One"))))
    val serialize: String = JsonMarshall.serialize(owner)
    println(serialize)
  }

  it should "de-serialize_a" in {
    val a: A = JsonMarshall.deserialize[A]("""{
                                             |    "type" : "C",
                                             |    "value" : "One"
                                             |  }""".stripMargin)
    println(a)
  }

  val json = """{
               |  "results" : [ [ "ExampleB", {
               |    "type" : "B",
               |    "value" : 1.0
               |  } ], [ "ExampleC", {
               |    "type" : "C",
               |    "value" : "One"
               |  } ] ]
               |}""".stripMargin

  it should "de-serialize" in {
    val owner: Owner = JsonMarshall.deserialize[Owner](json)
    println(owner)
  }

}

2 个答案:

答案 0 :(得分:0)

我相信这里有两个错误,其中一个与另一个相关的是Seq(元组)

1)地图不在序列化中导出类型信息

2)Seq(Tuple)忽略去序列化

的类型信息

Workround: - 使用包装类替换元组。

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXTERNAL_PROPERTY, property = "type")
@JsonSubTypes(Array(
  new Type(value = classOf[B], name = "B"),
  new Type(value = classOf[C], name = "C")))
trait A{}

case class B(value : Double) extends A
case class C(value : String) extends A

case class ContainerWithMap( results: Map[String, A])
case class ContainerWithTupleSeq( results: Seq[(String, A)])
case class ContainerWithWrappedSeq( results: Seq[WrapperClass])

case class WrapperClass(s : String, a : A)

class ATest extends FlatSpec with ShouldMatchers {
  behavior of "A"
  val map: Map[String, A] = Map("ExampleB" -> B(1.0), "ExampleC" -> C("One"))
  val seq: Seq[WrapperClass] = Seq(WrapperClass("ExampleB", B(1.0)), WrapperClass( "ExampleC",C("One")))

  it should "fail not supporting reciprocal serialize de-serialize behaviour for maps"  in {
    val owner : ContainerWithMap = ContainerWithMap(map)
    val serialize: String = JsonMarshall.serialize(owner)
    println(serialize)      // types not exported on serialization 
    val thrown = evaluating{JsonMarshall.deserialize[ContainerWithMap](serialize)} should produce [JsonMappingException]
    thrown.getMessage should startWith("Unexpected token (END_OBJECT), expected FIELD_NAME: missing property 'type' that is to contain type id")
  }

  it should "fail not supporting reciprocal serialize de-serialize behaviour for sequence of tuples"   in {
    val owner : ContainerWithTupleSeq = ContainerWithTupleSeq(map.toSeq)
    val serialize: String = JsonMarshall.serialize(owner)
    println(serialize)     // types ignored on de-Serialization
    val thrown = evaluating{JsonMarshall.deserialize[ContainerWithTupleSeq](serialize)} should produce [JsonMappingException]
    thrown.getMessage should startWith("Can not construct instance of com.egc.ost.pricing.contracts.response.A, problem: " +
      "abstract types either need to be mapped to concrete types, have custom deserializer, or be instantiated with additional type information")
  }

  it should "work if using a wrapper class"  in {
    val owner : ContainerWithWrappedSeq = ContainerWithWrappedSeq(seq)
    val serialize: String = JsonMarshall.serialize(owner)
    println(serialize)
    val deserialize: ContainerWithWrappedSeq = JsonMarshall.deserialize[ContainerWithWrappedSeq](serialize)
    println(deserialize)
    deserialize should be(owner)
  }

}

答案 1 :(得分:0)

此问题的修复程序出现在 2.2.3版本中。使用此版本可以避免使用包装类。