杰克逊将不同的字符串反序列化为相同的枚举常量

问题描述 投票:4回答:1

让我们假设我有一个看起来像这样的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

我知道我可以通过编写一个自定义反序列化程序来实现它,但我会尽量避免这种情况,因为我的程序中有很多很多枚举,而且每个程序都需要一个自定义反序列化程序就是一种矫枉过正。

理想情况下,正则表达式中的某种构造函数匹配任何字符串(“成功”,“失败”和“重试”除外)。

有没有办法在没有编写自定义解串器的情况下与杰克逊合作?

java serialization enums jackson
1个回答
2
投票

如果你的所有枚举都有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注释作为默认值,另外默认情况下它不处理小写枚举值。

© www.soinside.com 2019 - 2024. All rights reserved.