使用Jackson复制JSON字段

iszxjhcz  于 2022-11-09  发布在  其他
关注(0)|答案(5)|浏览(157)

我正在使用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"
}

我已经尝试使用previousanswers的建议,使用@JsonAutoDetect注解来指定只应使用类上的字段,并在ObjectMapper上设置相同的字段,但这并不能解决问题。
注解:

@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE,
        setterVisibility = JsonAutoDetect.Visibility.NONE, creatorVisibility = JsonAutoDetect.Visibility.NONE,
        isGetterVisibility = JsonAutoDetect.Visibility.NONE)

对象Map器:

ObjectMapper mapper = new ObjectMapper();
    mapper.getSerializationConfig().getDefaultVisibilityChecker()
            .withFieldVisibility(JsonAutoDetect.Visibility.ANY)
            .withGetterVisibility(JsonAutoDetect.Visibility.NONE)
            .withSetterVisibility(JsonAutoDetect.Visibility.NONE)
            .withCreatorVisibility(JsonAutoDetect.Visibility.NONE);
qni6mghb

qni6mghb1#

我通过在@JsonTypeInfo注解中使用JsonTypeInfo.As.EXISTING_PROPERTY解决了这个问题。
该项目是开源的,请在此处查看:ANS.java

nfg76nw0

nfg76nw02#

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

}

需要注意的是,这是使用fasterxml jackson jackson-databind 2.1.1实现的。

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.1.1</version>
</dependency>
cbjzeqam

cbjzeqam3#

此行为是由放置在类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)序列化为名称为mimeTypeproperty = "mimeType")的属性(JsonTypeInfo.As.PROPERTY)。通过@JsonSubTypes.Type,您可以将逻辑名称application/epub+zip分配给EpubBookmarkJsonModel
当涉及到序列化时,Jackson将逻辑名称序列化为属性mimeType = "application/epub+zip",然后将其中对象的属性mimeType序列化,其中mimeType恰好具有与逻辑名称application/epub+zip相同的值(在构造函数中赋值)。
我认为应该在@JsonTypeInfo注解中将mimeType更改为objectType,或者更好的做法是删除mimeType字段,因为Jackson将通过类型信息序列化来处理这个问题。

unhi4e5o

unhi4e5o4#

这种情况可能只发生在jacson lib的遗留版本中,只需将@JsonProperty(value = "Your_CUSTOM_Name")从字段移到getter即可解决。

6psbrbz9

6psbrbz95#

我也遇到了同样的问题。我们使用的是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,这样属性才会被填充。在我们的例子中,它是一个带有一些行为调度的枚举,所以我们当然需要它来实现我们的目的,而且能够将它用于Json子类型的区分也是很棒的。

@JsonTypeInfo(
  use = JsonTypeInfo.Id.NAME,
  property = "ruleType",
  visible = true)

相关问题