反序列化使用Jackson库的null值至枚举类型

huangapple 未分类评论47阅读模式
英文:

Deserialization null value to enum with Jackson

问题

我在JSON反序列化和映射到枚举方面遇到问题。我从外部API获取JSON,类似于以下两个示例:

{
 "someValue": null
}
{
 "someValue": "exists"
}

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

模型对象:

SomeEnum someValue;

以及枚举类:

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

对于 "exists" 值,模型类中包含了正确的枚举值,但如果我从API获取到 null,在模型中仍然是 null

我尝试过创建一些被 @JsonCreator 注解标记的方法,创建自己的枚举反序列化器,使用 @JsonEnumDefaultValue,但这些解决方案都不适用于我。有人知道如何将 null 反序列化为某个默认的枚举值吗?

英文:

I have problem with JSON deserialization and mapping it to enum. I'm getting JSON from external API simillar to this two examples:

{
 "someValue": null
}
{
 "someValue": "exists"
}

I would like to map null values to some default enum value.

Model object

SomeEnum someValue;

and enum class

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

For exists, value model class contains correct enum, but if I get null from API, it is still null in the model.

I tried to create some method annotated by @JsonCreator, creating own enum deserializer, using @JsonEnumDefaultValue but none of these solutions work for me. Do anyone knows, how can I deserialize nulls to some default enum?

答案1

得分: 0

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

你可以尝试像下面这样做(使用带有构造函数和使用 @JsonCreatorEnum):

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,你应该将这个绑定器放在你的控制器中:

@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));
    }
}
英文:

(Honestly, I wrote this code here without testing it, maybe you need to modify it a bit)

You can try to do something like following (Enum with a constructor and use @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;
    }
}

If it doesn't work, keep the above enum and try to make a custom converter (without Jackson) as following

If using spring boot You should put this binder in your controller

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

The following is the custom converter to specify how you convert your input value to an enum value.

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

答案2

得分: 0

好的,目前我通过创建自定义的枚举反序列化器来解决了这个问题。

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) {
        // 在这里实现逻辑
    }
}

然后使用 @JsonDeserialize 进行注册:

@JsonDeserialize(using = SomeEnumDeserializer.class)
public enum SomeEnum {
// 代码部分
}

但我仍然希望能够使用类似 @JsonProperty 的方式来处理 null 值,比如 @JsonNullProperty 或类似的方法。

英文:

Ok, so for now I solved this issue by creating custom enum deserializer.

class SomeEnumDeserializer extends StdDeserializer&lt;SomeEnum&gt; {
    SomeEnumDeserializer() {
        super(SomeEnum.class);
    }

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

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

and registering it using @JsonDeserialize:

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

But still I'd prefer using something like @JsonProperty but for null, like @JsonNullProperty or something like this.

答案3

得分: 0

设置字段的初始值为枚举值。

public class ExampleClass {
    @JsonProperty("someValue") public SomeEnum someValue = SomeEnum.NONE;
    
    public enum SomeEnum {
        @JsonProperty("exists") EXISTS,
        NONE;
    }
}

然而,这意味着如果该值不存在,它也将与指定null时的值相同。因此,以下两个 JSON 字符串将生成相同的 POJO:

{}
{"someValue":null}

不确定您是否希望出现这种行为。

英文:

Set the starting value of the field to the enum's value.

public class ExampleClass {
    @JsonProperty(&quot;someValue&quot;) public SomeEnum someValue = SomeEnum.NONE;
    
    public enum SomeEnum {
        @JsonProperty(&quot;exists&quot;) EXISTS,
        NONE;
    }
}

However, this will mean if the value doesn't exist it will also be the same value as if null was specified. So these two JSON strings will produce the same POJO:

{}
{&quot;someValue&quot;:null}

Not sure if that behavior is desired by you.

huangapple
  • 本文由 发表于 2020年4月6日 09:40:51
  • 转载请务必保留本文链接:https://java.coder-hub.com/61051783.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定