假设您从JSON格式的API调用中接收到对象列表,并且此对象引用了带JsonIdentityInfo注释的类。如果使用更多对象对列表进行resserialize,则如果JsonIdentityInfo带注释的对象在列表的添加元素中重复出现,您将获得2个JSON对象定义(当您尝试再次对其进行反序列化时,将导致InvalidDefinitionException)。看起来在反序列化过程中涉及了一些缓存,所以以前的值被重用了。是否可以避免这种行为?
我正在使用Kotlin开发Android,这意味着我使用Kotlin Jackson。
我编写了以下代码来说明正在发生的事情:
fun test_jsonIdentityInfo_reserialization(){
val bar = Bar(1, "bar")
val f1 = Foo("firstFoo", bar)
val f2 = Foo("secondFoo", bar)
val l1 = listOf(f1, f2)
val firstListString = JsonMapper.serialize(l1) ?: ""
println("First list serialized:")
println(firstListString)
println()
val firstListDeserialized = JsonMapper.deserialize<Collection<Foo>>(firstListString)?.toList() ?: emptyList()
println("First list desserialized:")
println(firstListDeserialized)
println()
val f3 = Foo("thirdFoo", bar)
val f4 = Foo("fortyFoo", bar)
val l2 = ... // See bellow what I tried
val secondListString = JsonMapper.serialize(l2) ?: ""
println("Second list serialized:")
println(secondListString)
println()
val secondListDeserialized = JsonMapper.deserialize<Collection<Foo>>(secondListString) ?: emptyList()
println("Second list desserialized:")
println(secondListDeserialized)
println()
}
data class Foo(
@JsonProperty("name")
val name: String = "",
@JsonProperty("bar")
val bar: Bar)
@JsonIdentityInfo(property = "id", generator = ObjectIdGenerators.PropertyGenerator::class, scope = Bar::class)
data class Bar(
@JsonProperty("id")
val id: Int = -1,
@JsonProperty("name")
val name: String = "")
object JsonMapper {
private val mapper: ObjectMapper by lazy {
ObjectMapper().registerKotlinModule().apply{
configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
enableDefaultTyping(ObjectMapper.DefaultTyping.JAVA_LANG_OBJECT)
}
}
inline fun <reified T> reify(): TypeReference<T> =
object : TypeReference<T>(){}
fun <T> serialize(data: T, ref: TypeReference<T>): String? =
mapper.writerFor(ref).writeValueAsString(data)
inline fun <reified T> serialize(data: T): String? =
serialize(data, reify())
fun <T> deserialize(data: String, type: TypeReference<T>): T? =
mapper.readValue(data, type)
inline fun <reified T> deserialize(data: String): T? =
deserialize(data, reify<T>())
}
我尝试了以下操作,更改了“ l2”值。
何时:
val l2 = listOf(f1, f2, f3, f4)
或:
val l2 = l1 + listOf(f3, f4)
退出:
First list serialized:
[{"name":"firstFoo","bar":{"id":1,"name":"bar"}},{"name":"secondFoo","bar":1}]
First list desserialized:
[Foo(name=firstFoo, bar=Bar(id=1, name=bar)), Foo(name=secondFoo, bar=Bar(id=1, name=bar))]
Second list serialized:
[{"name":"firstFoo","bar":{"id":1,"name":"bar"}},{"name":"secondFoo","bar":1},{"name":"thirdFoo","bar":1},{"name":"fortyFoo","bar":1}]
Second list desserialized:
[Foo(name=firstFoo, bar=Bar(id=1, name=bar)), Foo(name=secondFoo, bar=Bar(id=1, name=bar)), Foo(name=thirdFoo, bar=Bar(id=1, name=bar)), Foo(name=fortyFoo, bar=Bar(id=1, name=bar))]
这是期望的结果,其中“ bar”仅在第二次反序列化时才第一次被定义为对象。
何时:
val l2 = firstListDeserialized + listOf(f3, f4)
退出:
First list serialized:
[{"name":"firstFoo","bar":{"id":1,"name":"bar"}},{"name":"secondFoo","bar":1}]
First list desserialized:
[Foo(name=firstFoo, bar=Bar(id=1, name=bar)), Foo(name=secondFoo, bar=Bar(id=1, name=bar))]
Second list serialized:
[{"name":"firstFoo","bar":{"id":1,"name":"bar"}},{"name":"secondFoo","bar":1},{"name":"thirdFoo","bar":{"id":1,"name":"bar"}},{"name":"fortyFoo","bar":1}]
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `io.ubivis.ubivismobile.ExampleUnitTest$Bar`, problem: Already had POJO for id (java.lang.Integer) [[ObjectId: key=1, type=com.fasterxml.jackson.databind.deser.impl.PropertyBasedObjectIdGenerator, scope=io.ubivis.ubivismobile.ExampleUnitTest$Bar]]
at [Source: (String)"[{"name":"firstFoo","bar":{"id":1,"name":"bar"}},{"name":"secondFoo","bar":1},{"name":"thirdFoo","bar":{"id":1,"name":"bar"}},{"name":"fortyFoo","bar":1}]"; line: 1, column: 124] (through reference chain: java.util.ArrayList[2]->io.ubivis.ubivismobile.ExampleUnitTest$Foo["bar"])
这就是我得到的。注意,“ bar”在第二个序列化的“ firstFoo”和“ thirdFoo”中定义为对象。还要注意,“ firstListDeserialized”是一个不同的列表,不包含“ f1”和“ f2”(它们只是具有相同值的对象),并且是由“ l1”的反序列化导致的。我无法使用第一个解决方案,因为“ f1”和“ f2”将来自API调用,因此它们已经被序列化了。