MapStruct 条件映射:当目标字段非空时才执行源字段赋值
在MapStruct中,通过@AfterMapping或@Condition注解实现条件映射,仅当目标字段为空时才从源字段赋值,从而有效避免覆盖已有非空值。此方法特别适用于增量更新及DTO合并等场景。具体实现时需先忽略自动映射,再在回调方法中进行判空处理。
本文介绍如何在 MapStruct 中实现“仅当目标对象的某个字段不为 null 时,才将源字段映射过去”,避免覆盖已有值,适用于增量更新、DTO 合并等场景。
没错,这篇文章要讲的就是这个需求:在 MapStruct 的增量更新场景下,如何只让源字段赋值给目标对象中那些当前为 null 的字段,而如果目标字段已经有值,则保留不动。换句话说,就是“非空保护式映射”。
用例子说话:假设有一个 Car 对象,它的 engine 字段已经有点值了,现在从 CarDto 传进来一个 device 字段,你希望——只有当 car.engine 还是 null 的时候,才把 device 赋过去;如果 engine 已经非空,那就原封不动。这个逻辑在部分字段补全或合并更新中非常常见。
但 MapStruct 目前并没有一个 @Mapping(whenTargetNotNull = true) 这样开箱即用的注解。不过,别担心,通过组合策略,完全可以优雅地实现。
✅ 推荐方案:使用 @AfterMapping + 显式判空逻辑
@Mapper
public interface CarMapper {
// 先忽略 engine 字段的自动映射
@Mapping(target = "engine", ignore = true)
void updateCarFromDto(CarDto carDto, @MappingTarget Car car);
// 在映射完成后,按业务逻辑补充处理
@AfterMapping
default void handleEngineMapping(CarDto carDto, @MappingTarget Car car) {
// 安全校验:防止空指针
if (car == null || carDto == null) {
return;
}
// 关键逻辑:仅当目标 engine 为 null 时,才赋予新值
if (car.getEngine() == null && carDto.getDevice() != null) {
car.setEngine(carDto.getDevice());
}
// 注:若需“非空时才赋值”,则改为 `car.getEngine() != null`
}
}
? 提示:上面代码中if (car.getEngine() == null)表示“目标为空才映射”,这正好符合多数增量更新的场景(比如只补全缺失字段);如果业务逻辑反过来——目标非空才映射,那只需把条件改成car.getEngine() != null即可。
⚠️ 注意事项与最佳实践
这个方案虽然简单,但有几个细节得留意:
ignore = true是必须的——否则 MapStruct 会试图自动把device映射到engine,从而覆盖掉你@AfterMapping里写的逻辑;@AfterMapping方法签名必须与主映射方法一致,特别是参数顺序,并且目标对象要带上@MappingTarget注解;- 避免副作用:在
@AfterMapping里只操作目标对象(car),不要修改源对象(carDto); - 留意 Lombok 兼容性:如果
Car用了@Data或@Setter,那setEngine()可以正常调用;如果类是不可变的,就得改用构造器或 Builder 模式; - 性能方面:虽然多了几个运行时判断,但在绝大多数业务场景下,这个开销完全可以忽略不计。
✅ 替代方案(高级):使用 @Condition(MapStruct 1.5+)
如果你的项目已经升级到 MapStruct 1.5 或更高版本,那还有一个更声明式的写法——@Condition。它能让条件映射的意图更清晰,代码也更简洁:
@Mapper
public interface CarMapper {
@Mapping(target = "engine", source = "device")
void updateCarFromDto(CarDto carDto, @MappingTarget Car car);
@Condition
default boolean shouldMapEngine(CarDto carDto, @MappingTarget Car car) {
return car != null && car.getEngine() == null && carDto != null && carDto.getDevice() != null;
}
}
这样一来,MapStruct 会自己调用 shouldMapEngine 方法,只有当它返回 true 时,才执行 device → engine 的映射。相比 @AfterMapping,这种方式更接近函数式编程,也更容易维护,推荐新项目优先采用。
总的来说,MapStruct 虽然没有直接提供 whenTargetNull 这样的属性,但通过 @AfterMapping 或者 @Condition,我们都能清晰、安全、可维护地实现业务所需的空值保护逻辑。关键是要想清楚“到底什么条件下才映射”,然后选一个顺手的方式去实现。
Shapr3D是一款面向工业设计、机械工程、建筑概念和三维打印工作流的CAD软件。Mac版采用Parasolid建模内核,支持草图约束、实体建模、工程图、可视化渲染及常见CAD格式交换,并可通过账户在多台设备之间同步项目。
REAPER是Cockos开发的数字音频工作站,提供多轨音频与MIDI录制、剪辑、处理、混音和母带制作工具。Mac版兼容Intel与Apple芯片,支持AU、VST、VST3、CLAP等插件格式,并提供高度可定制的工作流程。
Ableton Live 是面向音乐制作人与现场表演者的数字音频工作站,提供编曲视图、独具特色的现场视图、音频录制、MIDI创作、实时变速、乐器及效果器。Mac版原生支持Apple芯片,并可连接音频接口、MIDI控制器和第三方插件。
Photoshop 2026 是 Adobe 推出的专业图像处理与视觉设计软件,支持 Windows、macOS 和 iPad 等平台,广泛应用于摄影修图、电商设计、平面海报、数字绘画及视觉合成等创作场景。
Blender 是一款免费开源、跨平台的专业 3D 创作软件,集建模、动画、渲染、视频编辑与视觉合成等功能于一体,广泛应用于影视动画、游戏设计和建筑可视化等领域。软件支持 Cycles 物理渲染器与 Eevee 实时渲染引擎,并提供多边形建模、骨骼绑定、物理模拟等专业工具。Blender 兼容 Windows、macOS 和 Linux 系统,安装包轻巧、运行流畅,依托活跃的全球开发者社区持续更新,是从初学者到专业创作者都值得选择的正版 3D 创作工具。














