【问题标题】:Duplicate JSON Field with Jackson与杰克逊重复 JSON 字段
【发布时间】:2013-08-16 17:30:40
【问题描述】:

我正在结合 Spring 使用 Jackson 进行 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"
}

我已经尝试使用previousanswers 的建议来使用@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);

【问题讨论】:

  • 我不知道它是否有帮助,但是如果您从AbstractBookmarkJsonModel 中删除注释@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "mimeType") ,那么您的json 中将只有一个mimeType

标签: java json jackson


【解决方案1】:

这种情况可能仅适用于 jacson lib 的旧版本 只需将您的 @JsonProperty(value = "Your_CUSTOM_Name") 从字段移动到吸气剂即可解决。

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    • 很好的解决方案,@JsonTypeInfo 上的 visible=true (如果不是,则序列化后属性为 null)
    • 在我看来,这应该是公认的答案。这是杰克逊最干净的用法。
    • 它在“toJson()”上工作,但是当我尝试“fromJson()”时,该字段留下了“null”值。有什么想法吗?
    • ANs.java 坏了。
    • 你拯救了我的一天!
    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

      此行为是由 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) 序列化为名称为 mimeType (property = "mimeType") 的属性 (JsonTypeInfo.As.PROPERTY)。使用@JsonSubTypes.Type,您可以将逻辑名称application/epub+zip 分配给EpubBookmarkJsonModel

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

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

      【讨论】:

      • +1 这是正确的答案,Jackson 在序列化的 JSON 输出中添加了一个附加属性来识别子类型。在您的情况下,您尝试使用现有属性,您不应该这样做。我知道您不能从课程中删除 mimeType 属性,因为我认为您需要它。只需使用另一个子类型信息属性名称,如 subtypeName,子类型名称使用类似“ImageBookmark”和“EpubBookmark”的名称。这是 Jacksons 多态类型处理的预期用途。
      • 我不认为这是一个足够的答案,因为这个解决方案需要 Jackson 的用户更改他们的数据模型以适应 Jackson 如何工作的一些内部细节(即更改字段的名称在子类型上)。此外,在高层次上,我不知道为什么有人会想要输出中的重复键,所以就我而言,这是一个错误!幸运的是,EXISTING_PROPERTY 解决方案对我们有用。
      • @CharlesCapps 嗯,也许你是对的,但是,我不认为 mimeType 是数据模型的一部分,它只是一个明显存在的 type flag为了 JSON 序列化。如果不必对模型进行序列化,我认为它不会存在。
      • 是的,我只是笼统地说。在我们的例子中,我们通常可能在我们的数据模型上有一些枚举来指示某物的类型。我们不应该更改我们的字段名称,因为 Jackson 的一些奇怪的内部细节会导致重复字段被发出。另外,如果子类从基类实现抽象方法,我认为这是一个逻辑字段。
      猜你喜欢
      • 2015-03-20
      • 2021-04-02
      • 2020-02-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-25
      相关资源
      最近更新 更多