我正在编写代码来解析来自服务的 JSON 响应,在该服务中我可以获得两种不同的格式,我想将它们映射到同一类型的对象。这是我的代码的简化示例:
data class MyClass @JsonCreator constructor(
@JsonProperty("name")
@JsonAlias("title")
val name: String
)
以下是一些可以在此设置中正常工作的 JSON blob:
{
"name": "Mr. Jones"
}
{
"title": "The Doctor"
}
但是,如果我的 JSON 包含这两个字段,则反序列化器会出错:
{
"name": "Mr. Jones",
"title": "The Doctor"
}
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No fallback setter/field defined for creator property 'name' (through reference chain: com.example.MyClass["name"])
我认为这是因为解串器不明白它应该使用这两个字段中的哪一个。如果两者都存在,是否可以指示它应该选择哪一个?我的意图是如果两者都存在,则更喜欢
name
而不是 title
,因此仅当 title
不存在时才应反序列化 name
。
我目前使用的是 Jackson 2.16.1,并且我的 Maven 项目中有 jackson-core
、
jackson-annotations
、
jackson-databind
、
jackson-dataformat-csv
和
jackson-module-kotlin
。这是我的 ObjectMapper 的主要配置:
val mapper: ObjectMapper = ObjectMapper()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.configure(DeserializationFeature.FAIL_ON_MISSING_EXTERNAL_TYPE_ID_PROPERTY, false)
.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true)
.configure(JsonParser.Feature.AUTO_CLOSE_SOURCE, false)
.configure(JsonGenerator.Feature.AUTO_CLOSE_TARGET, false)
.setSerializationInclusion(JsonInclude.Include.NON_NULL)
.registerKotlinModule()
我尝试寻找@JsonAlias
的替代方法(我发现没有任何方法可以做到这一点),并且还尝试设置替代的
@JsonCreator
方法。不幸的是,在实际情况中,我担心有四个字段,而且我不能只为 JSON 中可能出现的每种可能的字段组合编写新的创建者。
@JsonAlias
似乎也没有任何配置选项,而且我还没有在对象映射器的主反序列化器配置中找到一个选项 - 至少是我理解的一个选项。谢谢!
@JsonAlias
时,似乎不可能告诉 Jackson 使用一个字段而不是另一个字段。我使用的 java 记录仅具有 Jackson 用作 JsonCreator 的主记录构造函数(我相信这在 kotlin 数据类中是相同的)。消除 Jackson 错误的一个解决方法是创建实际上不执行任何操作的假 setter。
@JsonProperty("name")
private void setName(String ignore) {
// dummy setter which makes jackson happy when both values are set
}
@JsonProperty("title")
private void setTitle(String ignore) {
// dummy setter which makes jackson happy when both values are set
}
注意:这些假 setter 之所以起作用,是因为两个值之一(json 文档中的第一个值)被用作 Creator 属性,并且第二次出现时调用 setter。需要同时具备这两种方法,以确保 Jackson 可以反序列化 json 文档,无论
name
和
title
字段以什么顺序出现。