Deserializing enum Shape.OBJECT using Jackson fails
enums, jackson, java, json, serialization
Solution
Whilst I still agree with @renatoaraujoc's answer, I've found a (somehow hacky) solution to this problem.
Just create a `@JsonCreator` annotated method which receives a `Map<String, Object>`. Jackson deserializes the compound object into a Map as passes it to the method:
@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;
}
}
P.S.: You don't really need the `fromId` method, it can be all put into `fromObject`, but I use the first on other parts of the system and like to have this separation.
P.S.²: Jackson normally decode the `id` field into an `Integer` instance, so it enters the `if (obj.get("id") instanceof Integer)` on `fromObject`, but I've seen it being cast to `String` sometimes, that's why I'm checking.
Problem
I have the following enum declaration: ``` @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; } } ``` The input arrives as a json object and most of it is deserialized correctly, but the relevant part is as below, where `placement` is a `Compass`: ``` {"placement":{"name":"se","presentableName":"Lower Right"}} ``` Deserialization doesn't work. I thought a `JsonCreator` would work here, but for some reason I'm getting a org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'application/json;charset=UTF-8' not supported which is actually just a symptom of deserialization failure. If I change the creator to: ``` @JsonCreator public static Compass fromObject(@JsonProperty("name") String name) { return Compass.sw; } ``` It gets even more wierd, because now name equals `{` instead of `se` (which looks like a bug in the json object, but it's the same object that got deserialized a second ago so it's probably ok) I'm using `jackson 2.2.3` which is the latest right now.