鉴于这个简单的例子,第三个测试“反序列化”失败并显示消息。
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)
}
}
答案 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版本中。使用此版本可以避免使用包装类。