我最近遇到一个问题,Jackson Json 无法正常反序列化枚举类,尽管同一个枚举可以正常序列化。我查阅了一些资料并写下了这篇总结。
问题
enum Type{
A(11),
B(22);
@JsonValue
public final int code;
Type(int code) {
this.code = code;
}
}
上述枚举类可以正常序列化,序列化的结果是 code
字段的值:
objectMapper.writeValueAsString(Type.A); //值为11
但在反序列化时会报错:
objectMapper.readValue("11", Type.class); //报错
Caused by: com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `com.example.Example` from number 11: index value outside legal index range [0..1]
在网上搜索后,我发现这种方式应该是可行的。经过一系列排查,我发现问题出在当前使用的版本(2.11.x)无法支持 Integer 类型的反序列化,而 String 类型可以正常反序列化,例如 A("11")
。以下,我将介绍几种常见的枚举序列化与反序列化的方法。
使用 @JsonValue 注解
在字段或方法上使用 @JsonValue
注解可以让 Jackson Json 进行序列化与反序列化。但是,如果你的 Jackson 版本是 2.13.0 之前的版本,可能会遇到一些问题,例如无法对 Integer 类型进行反序列化,如上述例子所示。此时,你需要使用 @JsonCreator
自定义生成方法。
使用 @JsonCreator 自定义生成方法
在上述例子中,我们可以定义一个 static
方法(此处必须是 static 的),这样就可以从数字成功反序列化。
@JsonCreator
public static Type create(int code) {
for (Type value : Type.values()) {
if (value.code == code) {
return value;
}
}
return null;
}
使用 @JsonProperty 自定义值
你也可以使用 @JsonProperty
注解来标注序列化与反序列化的值,但这种方法可能会比较麻烦,尤其是当枚举属性太多时。例如:
enum Type{
@JsonProperty("11")
A(11),
@JsonProperty("22")
B(22);
//...
}
自定义 serializer 和 deserializer
当然,你也可以自定义 serializer 和 deserializer,这是最灵活的方法,但可能过于复杂,具体方法可以参阅这篇文章。在这里就不再赘述。
Jackson - Custom Serializer and Deserializer (howtodoinjava.com)