如何用ModelMapper映射对象并定义缺失/空属性的处理策略?
问题描述
我通过POST请求在其他微服务创建资源后,需要用PUT请求更新该资源——PUT端点要求必须发送资源的所有属性,哪怕属性值为空也不能省略。但通过GET请求获取资源时,空列表类型的impacts字段因为值为空没有返回,导致本地对象中该字段为null。现在需要用ModelMapper实现:将从GET获取的对象映射到用于PUT请求的目标对象时,所有字符串类型的未知值(null)填充为空字符串,所有列表类型的未知值填充为空列表,确保序列化时不会因为null省略属性。
实体类定义
public class Incident { private String assignee; // 注:原代码拼写错误为asignee,此处修正为与JSON字段一致的assignee private List<String> impacts; private String startDate; private String endDate; private String description; private String summary; // 省略getter、setter、无参/全参构造方法 }
GET请求返回的JSON
{ "assignee": "xpto", "startDate": "01-01-2020", "endDate": "02-01-2020", "description": "test", "summary": "summary test" }
解决方案
要实现这个需求,我们需要给ModelMapper配置自定义类型转换器,并调整映射策略,确保所有null值都被替换为对应类型的空值。
1. 编写自定义类型转换器
针对字符串和列表类型,分别实现转换器,把null值转换成空字符串或空列表:
字符串转换器
Converter<Object, String> stringNullConverter = context -> { Object source = context.getSource(); return source == null ? "" : source.toString(); };
列表转换器
Converter<Object, List<?>> listNullConverter = context -> { Object source = context.getSource(); return source == null ? new ArrayList<>() : (List<?>) source; };
2. 配置ModelMapper
将转换器注册到ModelMapper,并设置严格匹配策略,确保所有属性都被处理:
ModelMapper modelMapper = new ModelMapper(); // 注册转换器 modelMapper.addConverter(stringNullConverter); modelMapper.addConverter(listNullConverter); // 开启严格匹配,保证所有属性都被映射 modelMapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT); // 允许访问私有字段,确保实体类的私有属性能被正确映射 modelMapper.getConfiguration().setFieldMatchingEnabled(true); modelMapper.getConfiguration().setFieldAccessLevel(AccessLevel.PRIVATE);
3. 执行映射
假设从GET请求反序列化得到的对象是sourceIncident(其中impacts为null),直接用ModelMapper映射到新对象即可:
Incident sourceIncident = // 从GET接口获取并反序列化的对象 Incident targetIncident = modelMapper.map(sourceIncident, Incident.class); // 验证结果: // targetIncident.getImpacts() 会是 empty ArrayList // 所有字符串属性如果为null,都会被设置为""
4. 确保序列化时包含空值
最后要保证Jackson序列化时不会省略空值属性,有两种配置方式:
实体类级别配置
在Incident类上添加Jackson注解:
import com.fasterxml.jackson.annotation.JsonInclude; @JsonInclude(JsonInclude.Include.ALWAYS) public class Incident { // ... 属性定义 }
全局配置(Spring环境)
如果是Spring项目,可以在配置类中全局设置:
@Configuration public class JacksonConfig { @Bean public ObjectMapper objectMapper() { ObjectMapper objectMapper = new ObjectMapper(); // 强制序列化所有属性,包括空值 objectMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS); return objectMapper; } }
这样最终生成的JSON会包含所有属性,哪怕是空字符串或空列表,完全符合PUT端点的要求。
内容的提问来源于stack exchange,提问作者emanoellucas
相关产品推荐
相关产品推荐

