Json 当多态类型在Seq()中时,使用Scala模块在Jackson中进行多态反序列化失败
在这个简单的例子中,第三个测试“反序列化”失败,并显示消息Json 当多态类型在Seq()中时,使用Scala模块在Jackson中进行多态反序列化失败,json,scala,polymorphism,jackson,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 a
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]
尽管第二个测试“反序列化”证明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>
我相信这里有两个bug,一个与映射到Seq(tuple)相关 1) 映射不导出序列化的类型信息 2) Seq(Tuple)忽略反序列化的类型信息 解决方法:-使用包装类替换元组
@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)
}
}
这个问题的解决方案出现在版本2.2.3中。使用这个版本可以避免使用包装类。有趣的是,如果我用一个映射[String,A]替换Seq[(String,A)],并将json更改为{“results”:{“ExampleB”:{“type”:“B”,“value”:1.0},“ExampleC”:{“type”:“C”,“value”:“One”}}它确实反序列化,但是。。。序列化时,它会删除类型信息。在我看来,它像一只虫子。
@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)
}
}