反序列化 null 值以使用 Jackson 枚举

Posted

技术标签:

【中文标题】反序列化 null 值以使用 Jackson 枚举【英文标题】:Deserialization null value to enum with Jackson 【发布时间】:2020-07-17 23:28:21 【问题描述】:

我在 JSON 反序列化并将其映射到枚举时遇到问题。我从与这两个示例类似的外部 API 获取 JSON:


 "someValue": null


 "someValue": "exists"

我想将空值映射到某个默认枚举值。

模型对象

SomeEnum someValue;

和枚举类

public enum SomeEnum 
    @JsonProperty("exists") EXISTS,
    NONE;

对于存在,值模型类包含正确的枚举,但如果我从 API 获得 null,它仍然是模型中的 null

我尝试创建一些由@JsonCreator 注释的方法,创建自己的枚举反序列化器,使用@JsonEnumDefaultValue,但这些解决方案都不适合我。有谁知道,我怎样才能将空值反序列化为一些默认枚举?

【问题讨论】:

你能简单地说SomeEnum someValue = NONE;吗? 那没用,默认值被null覆盖了。 这在 json 中不存在该值时有效。如果值为 null,则此方法不起作用。 【参考方案1】:

(老实说,我在这里写了这段代码没有测试它,也许你需要稍微修改一下)

您可以尝试执行以下操作(Enum 带有构造函数并使用 @JsonCreator):

public enum SomeEnum 
    EXISTS("exists"),
    NONE(null);

    private String value;

    SomeEnum (String value) 
        this.value = value;
    

    @JsonCreator
    public static SomeEnum fromValue(String value) 
        for (SomeEnum someEnum : SomeEnum.values()) 
            if (StringUtils.equalsIgnoreCase(someEnum.getValue(), value)) 
                return someEnum;
            
        
        throw new IllegalArgumentException("Unknown value " + value);
    

    public String getValue () 
        return value;
    

如果它不起作用,请保留上面的枚举并尝试制作一个自定义转换器(没有 Jackson),如下所示

如果使用 spring boot 你应该把这个 binder 放在你的控制器中

@InitBinder
public void initBinder(final WebDataBinder webdataBinder) 
    webdataBinder.registerCustomEditor(SomeEnum.class, new SomeEnumConverter());

以下是自定义转换器,用于指定如何将输入值转换为枚举值。

public class SomeEnumConverter extends PropertyEditorSupport 
    @Override
    public void setAsText(final String text) 
        setValue(SomeEnum.fromValue(text));
    

【讨论】:

你可以使用@JsonValue public String getValue() @JsonValue 返回,但问题在于输入 查看文档。在枚举的情况下,它是双向的。 据我检查,@JsonCreator 仅用于现有值,对于空值被省略。我在答案中发布了我的解决方案。感谢您回答我的问题。顺便提一句。我没有尝试那个 binder 解决方案,但我尝试使用 org.springframework.core.convert.converter.Converter 实现自定义转换器,但效果不佳【参考方案2】:

好的,所以现在我通过创建自定义枚举反序列化器解决了这个问题。

class SomeEnumDeserializer extends StdDeserializer<SomeEnum> 
    SomeEnumDeserializer() 
        super(SomeEnum.class);
    

    @Override
    public SomeEnum getNullValue(DeserializationContext ctxt) 
        return SomeEnum.NONE;
    

    @Override
    public SomeEnum deserialize(JsonParser p, DeserializationContext ctxt) 
        // implementation here
    

并使用@JsonDeserialize 注册它:

@JsonDeserialize(using = SomeEnumDeserializer.class)
public enum SomeEnum 
// code

但我仍然更喜欢使用 @JsonProperty 之类的东西,但对于 null,例如 @JsonNullProperty 或类似的东西。

【讨论】:

以上是关于反序列化 null 值以使用 Jackson 枚举的主要内容,如果未能解决你的问题,请参考以下文章

Jackson 使用枚举键、POJO 值反序列化为 Map

枚举的反序列化不起作用 - Jackson [重复]

Jackson:将枚举值序列化和反序列化为整数

当值为“null”时,Jackson 忽略自定义字段反序列化器

Scala:如何使用null来防止Jackson反序列化

由@Conver注解引出的jackson对枚举的反序列化规则