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

时间:2017-12-23 09:07:59

标签: java serialization enums jackson

假设我有WITH RECURSIVE ParentsOfG1(id) AS ( SELECT privilege_group_id FROM privilege_group WHERE name = 'G1' UNION SELECT parent_id FROM privilege_relationship JOIN ParentsOfG1 ON id = child_id ) SELECT id FROM ParentsOfG1 WHERE id = (SELECT privilege_group_id FROM privilege_group WHERE name = 'P2'); ,看起来像这样。

enum Status

我从JSON接收public enum Status { SUCCESS, FAIL, RETRY, UNKNOWN } 属性,看起来像下面的示例。

  • status //有效案例,反序列化为{"status":"success"}
  • Status.SUCCESS //有效案例,反序列化为{"status":"fail"}
  • Status.FAIL //有效案例,反序列化为{"status":"retry"}

但是任何其他值都应该反序列化为Status.RETRY。实例

  • Status.UNKNOWN //无效案例,反序列化为{"status":"blabla"}
  • Status.UNKNOWN //无效案例,反序列化为{"status":"John"}

我知道我可以通过编写自定义反序列化程序来完成它,但是我试图避免这种情况,因为我的程序中有很多很多枚举,并且需要为每个枚举程序设置一个自定义反序列化程序,这将是一种过度杀伤力。

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

有没有办法在没有编写自定义反序列化器的情况下与杰克逊合作?

1 个答案:

答案 0 :(得分: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注释作为默认值,另外默认情况下它不处理小写枚举值。