java - jackson 将不同的字符串反序列化为相同的枚举常量

标签 java serialization enums jackson

假设我有一个如下所示的 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/

相关文章:

python - 动态创建的Enum的方法重载

java - Android Studio 在编译时未检测到支持库

java - 从 java 填充 SQL 表时出错

java - 注释 Java 方法以记录其结果和异常

java - 对象流 : is there a way to read serialized object as properties map?

java - Java 中枚举和基于枚举的类实现之间的优缺点是什么?

java - 将 StringTokenizer 替换为 String.split(..)

java - JettisonMappedXmlDriver 和 XStream 的 pretty-print

.net - 在 .NET 中序列化数据传输对象

c++ - 从 C++ 基类中的函数返回枚举