使用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
相关产品推荐
相关产品推荐

