JSON 中的字段名称"Parts"导致反序列化失败



在下面的代码中,我可以触发反序列化失败,

因为
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.util.ArrayList<de.richtercloud.jackson.deserialize.list.of.objects.DeserializationTest$D>` out of FIELD_NAME token
at [Source: (String)"{
"a": [
{
"c": {
"Parts": []
}
}
]
}"; line: 5, column: 25] (through reference chain: de.richtercloud.jackson.deserialize.list.of.objects.DeserializationTest$A["a"]->java.util.ArrayList[0]->de.richtercloud.jackson.deserialize.list.of.objects.DeserializationTest$B["c"])
at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59)
at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1442)
at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1216)
at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1168)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.handleNonArray(CollectionDeserializer.java:332)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:265)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:245)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:27)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1284)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:326)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:159)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:530)
at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeWithErrorWrapping(BeanDeserializer.java:528)
at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:417)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1287)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:326)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:159)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:286)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:245)
at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:27)
at com.fasterxml.jackson.databind.deser.SettableBeanProperty.deserialize(SettableBeanProperty.java:530)
at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeWithErrorWrapping(BeanDeserializer.java:528)
at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeUsingPropertyBased(BeanDeserializer.java:417)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromObjectUsingNonDefault(BeanDeserializerBase.java:1287)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:326)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:159)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4202)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3205)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3173)
at de.richtercloud.jackson.deserialize.list.of.objects.DeserializationTest.testDeserialization(DeserializationTest.kt:22)
[omitted JUnit stacktrace]

通过在以下测试中更改Parts字段的名称(同时在 JSON 和类中(:

internal class DeserializationTest {
@Test
fun testDeserialization() {
val serialized = """{
"a": [
{
"c": {
"Parts": []
}
}
]
}"""
val deserialized = createObjectMapper().readValue(serialized, A::class.java)
assertNotNull(deserialized)
}
fun createObjectMapper() = ObjectMapper().registerModule(KotlinModule())
data class A(val a: List<B>)
data class B(val c: C)
data class C(val Parts: List<D>)
data class D(var e: String)
}

我希望无论我选择哪个名称,此测试都可以工作,因为字段名称是数据,并且不会对反序列化算法的行为产生任何影响。

我尝试了partsa和许多其他名称,并在网上和jackson-databind源代码中搜索"零件"是一个关键字的提示。

.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true)添加到ObjectMapper初始化会导致异常消息更改为com.fasterxml.jackson.module.kotlin.MissingKotlinParameterException: Instantiation of [simple type, class de.richtercloud.jackson.deserialize.list.of.objects.DeserializationTest$D] value failed for JSON property e due to missing (therefore NULL) value for creator parameter e which is a non-nullable type

我使用以下版本:

<properties>
<kotlin.version>1.3.61</kotlin.version>
<junit5.version>5.5.2</junit5.version>
<jackson.version>2.10.1</jackson.version>
</properties>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-reflect</artifactId>
<version>${kotlin.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.module</groupId>
<artifactId>jackson-module-kotlin</artifactId>
<version>${jackson.version}</version>
</dependency>
<!-- test dependencies -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${junit5.version}</version>
<scope>test</scope>
</dependency>
</dependencies>

我可以通过指定来解决异常

data class C(@JsonProperty("Parts") val parts: List<D>)

但是我想了解这个问题/行为。

这是杰克逊的一个"特征": https://github.com/FasterXML/jackson-module-kotlin/issues/92

建议的解决方案是像您已经使用的那样使用@JsonProperty

不过,只有snake_case键也应该可以正常工作:

internal class DeserializationTest {
@Test
fun testDeserialization() {
val serialized = """{
"a": [
{
"c": {
"parts": []
}
}
]
}"""
val deserialized = createObjectMapper().readValue(serialized, A::class.java)
assertNotNull(deserialized)
}
fun createObjectMapper() = ObjectMapper().registerModule(KotlinModule())
data class A(val a: List<B>)
data class B(val c: C)
data class C(val parts: List<D>)
data class D(var e: String)
}

最新更新