假设我有一个如下所示的 enum Status
。
public enum Status {
SUCCESS,
FAIL,
RETRY,
UNKNOWN
}
我正在从 JSON 中接收 status
属性,它可能类似于以下示例。
{"status":"success"}
//有效情况,反序列化为Status.SUCCESS
{"status":"fail"}
//有效情况,反序列化为Status.FAIL
{"status":"retry"}
//有效情况,反序列化为Status.RETRY
但任何其他值都应反序列化为 Status.UNKNOWN
。示例。
{"status":"blabla"}
//大小写无效,反序列化为Status.UNKNOWN
{"status":"John"}
//大小写无效,反序列化为Status.UNKNOWN
我知道我可以通过编写自定义反序列化器来做到这一点,但我会尽量避免这种情况,因为我的程序中有很多很多枚举,并且为每个枚举都要求一个自定义反序列化器会有点矫枉过正。
理想情况下,正则表达式中的某种构造函数可以匹配任何字符串(“成功”、“失败”和“重试”除外)。
有没有一种方法可以在不编写自定义反序列化器的情况下使用 Jackson 来实现?
最佳答案
如果您所有的枚举都有 UNKNOWN
值,您可以像这样编写一个自定义反序列化器:
class EnumDeserializer extends JsonDeserializer<Enum> {
private final Class<? extends Enum> enumType;
public EnumDeserializer(Class<? extends Enum> enumType) {
this.enumType = enumType;
}
@Override
public Enum deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException {
try {
String stringValue = jp.getValueAsString().toUpperCase();
return Enum.valueOf(enumType, stringValue.toUpperCase());
} catch (IllegalArgumentException e) {
return Enum.valueOf(enumType, "UNKNOWN");
}
}
}
并配置您的映射器以使用它:
SimpleModule module = new SimpleModule();
module.setDeserializerModifier(new BeanDeserializerModifier() {
@Override
public JsonDeserializer<Enum> modifyEnumDeserializer(DeserializationConfig config,
final JavaType type,
BeanDescription beanDesc,
final JsonDeserializer<?> deserializer) {
return new EnumDeserializer((Class<Enum<?>>) type.getRawClass());
}
});
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(module);
或者,您可以使用 jackson 反序列化功能为未知枚举属性设置默认值:
enum MyEnum { A, B, @JsonEnumDefaultValue UNKNOWN }
...
final ObjectMapper mapper = new ObjectMapper();
mapper.enable(DeserializationFeature.READ_UNKNOWN_ENUM_VALUES_USING_DEFAULT_VALUE);
MyEnum value = mapper.readValue("\"foo\"", MyEnum.class);
assertSame(MyEnum.UNKNOWN, value);
但使用这种方法,您需要更改所有枚举以使用 @JsonEnumDefaultValue
注释作为默认值,而且默认情况下它不处理小写枚举值。
关于java - jackson 将不同的字符串反序列化为相同的枚举常量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47951187/