使用Jackson反序列化枚举Shape.OBJECT失败

The*_*uck 9 java enums serialization json jackson

我有以下枚举声明:

@Document
@JsonFormat(shape= JsonFormat.Shape.OBJECT)
@JsonAutoDetect()
public enum Compass {
    north("Upper Center"),
    south("Lower Center"),
    east("Left Center"),
    west("Right Center"),
    ne("Upper Right"),
    nw("Upper Left"),
    se("Lower Right"),
    sw("Lower Left"),
    ;

    @JsonProperty   
    private String presentableName;
    @JsonProperty   
    private String name;

    private Compass() {}
    private Compass(String presentableName) {
        this.presentableName = presentableName;
    }

    public String getPresentableName() {
        return presentableName;
    }
    public void setPresentableName(String presentableName) {
        this.presentableName = presentableName;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    @JsonCreator
    public static Compass fromObject(@JsonProperty("name") String name, @JsonProperty("presentableName") String presentableName) { 
        return Compass.sw;
    }
}
Run Code Online (Sandbox Code Playgroud)

输入到达一个JSON对象,大部分是正确的反序列化,但相关部分如下,其中placementCompass:

{"placement":{"name":"se","presentableName":"Lower Right"}}
Run Code Online (Sandbox Code Playgroud)

反序列化不起作用.我以为JsonCreator会在这里工作,但出于某种原因,我得到了一个

org.springframework.web.HttpMediaTypeNotSupportedException:不支持内容类型'application/json; charset = UTF-8'

这实际上只是反序列化失败的一个症状.

如果我将创建者更改为:

@JsonCreator
public static Compass fromObject(@JsonProperty("name") String name) { 
    return Compass.sw;
}
Run Code Online (Sandbox Code Playgroud)

它变得更加奇怪,因为现在名称等于{而不是se(它看起来像json对象中的一个bug,但是它是同一个在一秒钟之前被反序列化的对象所以它可能没问题)

我正在使用jackson 2.2.3哪个是最新的.

Din*_*nei 6

虽然我仍然同意@renatoaraujoc 的回答,但我已经找到了一个(不知何故hacky)解决这个问题的方法。

只需创建一个带@JsonCreator注释的方法,该方法接收Map<String, Object>. Jackson 将复合对象反序列化为 Map 并将其传递给方法:

@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum TesterEnum {
    FirstValue(1, "One"),
    SecondValue(2, "Two");

    private int id;
    private String dsc;

    TesterEnum(int id, String dsc) {
        this.id = id;
        this.dsc = dsc;
    }

    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getDsc(){
        return dsc;
    }
    public void setDsc(String dsc){
        this.dsc = dsc;
    }

    @JsonCreator
    public static TesterEnum fromObject(final Map<String, Object> obj) {
        if (obj != null && obj.containsKey("id")) {
            Integer id = null;
            if (obj.get("id") instanceof Integer) {
                id = (Integer)obj.get("id");
            } else {
                id = Integer.parseInt((String)obj.get("id"));
            }
            return fromId(id);
        }
        return null;
    }
    public static TesterEnum fromId(final Integer id) {
        if (id != null) {
            for (TesterEnum e : TesterEnum.values()) {
                if (id.equals(e.getId())) return e;
            }
        }
        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

PS:你fromId其实不需要方法,都可以放进去fromObject,但是我在系统的其他部分使用第一个,喜欢有这种分离。

PS²:杰克逊通常将id字段解码为一个Integer实例,因此它进入if (obj.get("id") instanceof Integer)on fromObject,但我String有时看到它被强制转换为,这就是我检查的原因。


ren*_*joc 3

如果将鼠标悬停在注释 @JsonFormat 上,其文本中明确指出 Enum 可以序列化,但如果您选择 JsonFormat,则无法反转它们。形状.对象. 因此,如果您希望能够来回使用枚举,请不要添加此注释。希望以后对你有帮助。