升级Jackson-databind 2.x后缺失字段反序列化为null如何配置为空对象?
解决方案
问题根源
你当前的配置中,Jackson反序列化时会优先使用@AllArgsConstructor生成的public全参构造实例化对象,输入缺失的字段会直接传入null作为构造参数,覆盖无参构造内的初始化值。同时你将CREATOR的可见性设为NONE,导致Jackson无法识别私有无参构造,无法通过它保留初始化默认值。
另外注意你示例POJO存在笔误:Map类型的value2在无参构造中被赋值为ImmutableList.of(),类型不匹配,实际使用需改为ImmutableMap.of()。
方案1:调整构造实例化逻辑(优先推荐)
无需修改POJO,仅调整ObjectMapper配置即可,让Jackson优先调用无参构造实例化对象,再填充输入中存在的字段,缺失字段保留无参构造中的初始值:
IonObjectMapper joiObjectMapper = (IonObjectMapper) new IonObjectMapper() // 新增3行配置 .setVisibility(PropertyAccessor.CREATOR, JsonAutoDetect.Visibility.ANY) .enable(MapperFeature.ALLOW_FINAL_FIELDS_AS_MUTATORS) .setConstructorDetector(new ConstructorDetector(ConstructorDetector.UsePriority.DEFAULT, true, false)) // 原有配置保持不变 .setSerializationInclusion(JsonInclude.Include.ALWAYS) .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) .enable(SerializationFeature.WRITE_EMPTY_JSON_ARRAYS) .enableDefaultTyping(ObjectMapper.DefaultTyping.JAVA_LANG_OBJECT, JsonTypeInfo.As.PROPERTY) .enable(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY) .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS) .enable(MapperFeature.AUTO_DETECT_SETTERS) .setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY) .setVisibility(PropertyAccessor.GETTER, JsonAutoDetect.Visibility.NONE) .setVisibility(PropertyAccessor.SETTER, JsonAutoDetect.Visibility.NONE) .setVisibility(PropertyAccessor.IS_GETTER, JsonAutoDetect.Visibility.NONE);
- 调整
CREATOR可见性为ANY:允许Jackson访问私有构造函数 - 开启
ALLOW_FINAL_FIELDS_AS_MUTATORS:允许Jackson修改@Value注解生成的final字段值 - 设置构造检测策略:优先使用无参构造实例化对象
方案2:全局空值替换(适用于构造调整不生效场景)
如果Lombok注解优先级导致构造策略不生效,可通过注册自定义模块全局为集合类型设置默认空值,输入中字段缺失或显式传null都会自动替换为空集合:
joiObjectMapper.registerModule(new SimpleModule() { @Override public void setupModule(SetupContext context) { super.setupModule(context); context.addBeanDeserializerModifier(new BeanDeserializerModifier() { @Override public List<BeanPropertyDefinition> updateProperties(DeserializationConfig config, BeanDescription beanDesc, List<BeanPropertyDefinition> propDefs) { for (int i = 0; i < propDefs.size(); i++) { BeanPropertyDefinition prop = propDefs.get(i); if (Map.class.isAssignableFrom(prop.getRawType())) { propDefs.set(i, prop.withNullProvider(p -> ImmutableMap.of())); } else if (List.class.isAssignableFrom(prop.getRawType())) { propDefs.set(i, prop.withNullProvider(p -> ImmutableList.of())); } else if (Set.class.isAssignableFrom(prop.getRawType())) { propDefs.set(i, prop.withNullProvider(p -> ImmutableSet.of())); } } return propDefs; } }); } });
以上两种方案均适配Jackson 2.10.x版本,无需修改任何POJO代码。
内容的提问来源于stack exchange,提问作者I.shL
相关产品推荐
相关产品推荐

