我使用 Jackson 与 Spring 结合进行 JSON(反)序列化。然而,在某些情况下,我遇到了字段两倍的问题。
我有一个抽象类:
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "mimeType")
@JsonSubTypes({
@JsonSubTypes.Type(value = ImageBookmarkJsonModel.class, name = "image/jpeg"),
@JsonSubTypes.Type(value = EpubBookmarkJsonModel.class, name = "application/epub+zip")
})
public abstract class AbstractBookmarkJsonModel extends AbstractJsonModel {
protected String mimeType;
// Removed other fields for brevity
public String getMimeType() {
return mimeType;
}
public void setMimeType(String mimeType) {
this.mimeType = mimeType;
}
@Override
public String toString() {
ObjectMapper mapper = new ObjectMapper();
try {
return mapper.writeValueAsString(this);
} catch (IOException e) {
throw new IllegalStateException("Cannot convert object of type " + this.getClass().toString() + " to JSON", e);
}
}
}
具体类扩展了抽象:
public class EpubBookmarkJsonModel extends AbstractBookmarkJsonModel {
private static final long serialVersionUID = 1L;
// Removed other fields for brevity
public EpubBookmarkJsonModel() {
this.mimeType = "application/epub+zip";
}
}
问题是,当我序列化这个 JSON 时,我得到一个重复的
mimeType
字段:
{
"mimeType": "application/epub+zip",
"mimeType": "application/epub+zip",
"userId": 24,
"acid": "ACID-000000000029087",
"added": "2013-08-14T12:02:17Z",
"epubBookmarkId": 34,
"cfi": "epubcfi(/6/4!/2/68)",
"context": "CONTEXT"
}
@JsonAutoDetect
注释来指定仅应使用类上的字段以及在 ObjectMapper
上设置相同的字段,但这并不能修复问题。
注释:
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE,
setterVisibility = JsonAutoDetect.Visibility.NONE, creatorVisibility = JsonAutoDetect.Visibility.NONE,
isGetterVisibility = JsonAutoDetect.Visibility.NONE)
对象映射器:
ObjectMapper mapper = new ObjectMapper();
mapper.getSerializationConfig().getDefaultVisibilityChecker()
.withFieldVisibility(JsonAutoDetect.Visibility.ANY)
.withGetterVisibility(JsonAutoDetect.Visibility.NONE)
.withSetterVisibility(JsonAutoDetect.Visibility.NONE)
.withCreatorVisibility(JsonAutoDetect.Visibility.NONE);
我在重复输出时遇到了完全相同的问题。我找到了一个不涉及其他属性的解决方案,并且允许我不删除原始属性。首先,我将 JsonTypeInfo 的可见标志设置为 true。然后,我向属性声明和 getter(但不是 setter)添加了 JsonIgnore 注释。到目前为止,仅使用 type 属性的一个键即可正确输出 JSON。
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, visible = true, property = "mimeType")
@JsonSubTypes({
@JsonSubTypes.Type(value = ImageBookmarkJsonModel.class, name = "image/jpeg"),
@JsonSubTypes.Type(value = EpubBookmarkJsonModel.class, name = "application/epub+zip")
})
public abstract class AbstractBookmarkJsonModel extends AbstractJsonModel {
@JsonIgnore
@JsonProperty("mimeType")
protected String mimeType;
@JsonIgnore
@JsonProperty("mimeType")
public String getMimeType() {
return mimeType;
}
@JsonProperty("mimeType")
public void setMimeType(String mimeType) {
this.mimeType = mimeType;
}
}
请注意,这是使用 fastxml jackson jackson-databind 2.1.1
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.1.1</version>
</dependency>
此行为是由类上的注释引起的
AbstractBookmarkJsonModel
:
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "mimeType")
@JsonSubTypes({
@JsonSubTypes.Type(value = ImageBookmarkJsonModel.class, name = "image/jpeg"),
@JsonSubTypes.Type(value = EpubBookmarkJsonModel.class, name = "application/epub+zip")
})
@JsonTypeInfo
告诉 Jackson 将逻辑类型名称 (JsonTypeInfo.Id.NAME
) 序列化为名称为 JsonTypeInfo.As.PROPERTY
(mimeType
) 的属性 (property = "mimeType"
)。使用 @JsonSubTypes.Type
,您可以将逻辑名称 application/epub+zip
分配给 EpubBookmarkJsonModel
。
说到序列化,Jackson 将逻辑名序列化为属性
mimeType = "application/epub+zip"
,然后将其中对象的属性
mimeType
恰好与逻辑名称 application/epub+zip
(在构造函数中分配)具有相同的值。
我认为
mimeType
注释中的 objectType
应该更改为 @JsonTypeInfo
,或者最好删除 mimeType
字段,因为 Jackson 将通过类型信息序列化来处理这个问题。
这种情况可能只是旧版本的 jacson lib 只需将您的
@JsonProperty(value = "Your_CUSTOM_Name")
从字段移至 getters 即可解决。
有同样的问题。我们正在使用 Lombok,我通过 @JsonProperty 访问获得了这项工作:
@Getter
@Setter
@JsonProperty(access = JsonProperty.Access.WRITE_ONLY) // Prevents duplication when serializing to JSON (subtype discriminator property)
private RuleType ruleType;
我喜欢这个解决方案,因为:
是的,需要visible=true,以便填充该属性。在我们的例子中,它是一个带有一些行为调度的 Enum,所以我们当然需要它来实现我们的目的,并且能够将它用于 Json 子类型区分也很棒。
@JsonTypeInfo(
use = JsonTypeInfo.Id.NAME,
property = "ruleType",
visible = true)
对我来说,当我不小心使字段和 JSON 属性(例如 .
@JsonProperty("Feild1") private String Field1;
我是这样修复的
@JsonProperty("Feild1") private String field1;