You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Jackson将含空值Map的JSON反序列化为不可变类

问题:Jackson反序列化含空值的Map到不可变类时抛出异常

场景还原

需要反序列化包含空值Map的JSON对象到不可变Java类,但Jackson抛出ValueInstantiationException,提示null value in entry: b=null。

JSON结构:

{
    "id": "1",
    "links": {
          "a": "someLink",
          "b": null
     }
}

不可变类定义:

@Value.Immutable
@JsonSerialize(as = ImmutableMyClass.class)
@JsonDeserialize(as = ImmutableMyClass.class)
public interface MyClass {

    @JsonProperty("id")
    String getId();

    @JsonProperty("links")
    Map<String, String> getLinks();
}

反序列化代码:

List<MyClass> myClassList = objectMapper.readValue(
    jsonString, 
    objectMapper.getTypeFactory().constructCollectionType(List.class, ImmutableMyClass.class)
);

报错信息:

com.fasterxml.jackson.databind.exc.ValueInstantiationException problem: null value in entry: b=null

问题原因

Immutables框架默认生成的不可变类会严格校验Map类型字段,不允许Map中包含null值(包括key或value)。当Jackson将JSON中的b:null解析后传入Immutable类的构造器时,会触发校验失败,抛出异常。

解决方案

方案1:允许Map中存储null值

在getLinks()方法上添加@Nullable注解(可使用org.immutables.value.Nullable或javax.annotation.Nullable),让Immutables生成的类接受Map中的null值:

@Value.Immutable
@JsonSerialize(as = ImmutableMyClass.class)
@JsonDeserialize(as = ImmutableMyClass.class)
public interface MyClass {

    @JsonProperty("id")
    String getId();

    @JsonProperty("links")
    @Nullable // 允许Map包含null值
    Map<String, String> getLinks();
}

方案2:将null值转换为空字符串存入Map

如果不想在Map中保留null,可将其转为空字符串,有两种实现方式:

方式A:自定义Map反序列化器

编写专门处理Map的反序列化器,将null值替换为空字符串:

public class NullToEmptyStringMapDeserializer extends JsonDeserializer<Map<String, String>> {
    @Override
    public Map<String, String> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        Map<String, String> map = p.readValueAs(new TypeReference<>() {});
        if (map == null) {
            return Collections.emptyMap();
        }
        // 将所有null值替换为空字符串
        map.replaceAll((key, value) -> value == null ? "" : value);
        return map;
    }
}

在getLinks()方法上指定使用该反序列化器:

@JsonProperty("links")
@JsonDeserialize(using = NullToEmptyStringMapDeserializer.class)
Map<String, String> getLinks();

方式B:全局配置ObjectMapper

如果希望所有String类型的null值都自动转为空字符串,可全局配置ObjectMapper:

ObjectMapper objectMapper = new ObjectMapper();
// 配置String类型的null值反序列化为空字符串
objectMapper.configOverride(String.class)
    .setSetterInfo(JsonSetter.Value.forValueNulls(Nulls.AS_EMPTY));

此配置会作用于所有String类型字段,包括Map中的value,无需修改实体类。


内容的提问来源于stack exchange,提问作者prestigem

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 03:52:57