42

我将 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);
4

5 回答 5

60

我通过JsonTypeInfo.As.EXISTING_PROPERTY在 @JsonTypeInfo 注释中使用解决了这个问题。

该项目是开源的,在这里查看:ANS.java

于 2015-09-28T14:14:05.293 回答
11

我在重复输出时遇到了同样的问题。我找到了一个不涉及其他属性的解决方案,并允许我不删除原始属性。首先,我将 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>
于 2014-05-19T16:46:26.277 回答
8

此行为是由放置在 class 上的注释引起的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.PROPERTYmimeTypeproperty = "mimeType"@JsonSubTypes.Typeapplication/epub+zipEpubBookmarkJsonModel

在序列化方面,Jackson 将逻辑名称序列化为属性mimeType = "application/epub+zip",然后将其中的对象的属性 序列化,这些属性mimeType恰好与逻辑名称具有相同的值application/epub+zip(在构造函数中分配)。

我认为mimeType应该objectType@JsonTypeInfo注释中更改为,甚至更好地删除该mimeType字段,因为杰克逊将通过类型信息序列化来处理这个问题。

于 2013-08-14T18:16:52.933 回答
0

这种情况可能只是使用 jacson lib 的旧版本,只需将您@JsonProperty(value = "Your_CUSTOM_Name")的从字段移到 getter 即可解决。

于 2022-01-26T11:57:55.470 回答
0

有同样的问题。我们正在使用 Lombok,我通过 @JsonProperty 访问获得了这项工作:

  @Getter
  @Setter
  @JsonProperty(access = JsonProperty.Access.WRITE_ONLY) // Prevents duplication when serializing to JSON (subtype discriminator property)
  private RuleType ruleType;

我喜欢这个解决方案,因为:

  • 不依赖另一个库
  • 不必更改我的数据模型
  • 与 Lombok 一起使用(不那么混乱)

是的,需要 visible=true 以便填充该属性。在我们的例子中,它是一个带有一些行为调度的 Enum,所以我们当然需要它来实现我们的目的,并且能够将它用于 Json 子类型区分也很棒。

@JsonTypeInfo(
  use = JsonTypeInfo.Id.NAME,
  property = "ruleType",
  visible = true)
于 2022-02-23T18:27:34.390 回答