Java中如何配置ModelMapper跳过对象内的Null对象映射?
问题分析
你遇到的核心问题是ModelMapper的map方法使用错误,同时对setSkipNullEnabled(true)的生效逻辑理解有偏差:
- 你预先通过
newInstance()创建了带有嵌套空DTO实例的initializedFilterDto,但随后用modelMapper.map(filterDto, OperationDto.class)创建了全新的OperationDto对象,直接覆盖了之前初始化的实例,导致预先创建的嵌套空对象全部丢失。 - 当源对象
filterDto中的嵌套属性(如driverDto)为null时,新创建的目标对象对应属性会被设置为null,这就是你看到的“源Null对象被映射到目标”的现象。
解决方案
方案一:使用更新式映射(保留目标对象原有值)
修改映射逻辑,将源对象的属性映射到已初始化的目标对象上,而非创建新对象。此时setSkipNullEnabled(true)会生效:源对象的null属性不会覆盖目标对象已有的嵌套空实例。
public List<OperationDto> getAllByFilter(OperationDto filterDto) throws TalyumException { // 初始化带有嵌套空实例的目标对象 OperationDto initializedFilterDto = (OperationDto) new OperationDto().newInstance(); // 配置ModelMapper:跳过源的null属性,保留目标原有值 modelMapper.getConfiguration().setSkipNullEnabled(true); modelMapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT); // 关键:将源对象映射到已存在的目标对象,而非创建新实例 modelMapper.map(filterDto, initializedFilterDto); List<OperationEntity> operationEntityList = operationRepository.findAllByFilter(initializedFilterDto); return operationEntityList.stream().map(entity -> modelMapper.map(entity, OperationDto.class)).toList(); }
方案二:自定义转换器(自动初始化嵌套DTO)
如果希望所有OperationDto实例在创建时自动初始化嵌套对象,无需手动调用newInstance(),可以给ModelMapper添加自定义转换器:
// 在ModelMapper配置类中添加转换器(确保ModelMapper是单例) modelMapper.addConverter(new Converter<OperationEntity, OperationDto>() { @Override public OperationDto convert(MappingContext<OperationEntity, OperationDto> context) { OperationDto dto = new OperationDto(); // 自动初始化所有嵌套DTO dto.setDriverDto(new UserDto()); dto.setOperatorDto(new UserDto()); dto.setVehicleDto(new VehicleDto()); dto.setFromLocationDto(new LocationDto()); dto.setToLocationDto(new LocationDto()); // 让ModelMapper完成剩余属性的映射 modelMapper.map(context.getSource(), dto); return dto; } });
注意事项
setSkipNullEnabled(true)仅对源对象的null属性生效:当源属性为null时,不会覆盖目标对象的对应属性值;如果源属性有值,会正常覆盖目标属性。- 确保ModelMapper是单例实例(如Spring环境中用
@Bean注入),避免每次方法调用重复创建导致配置失效。
内容的提问来源于stack exchange,提问作者Akcan
相关产品推荐
相关产品推荐

