
本文介绍如何在 mapstruct 中实现“仅当目标对象的某个字段不为 null 时,才将源字段映射过去”,避免覆盖已有值,适用于增量更新、dto 合并等场景。
本文介绍如何在 mapstruct 中实现“仅当目标对象的某个字段不为 null 时,才将源字段映射过去”,避免覆盖已有值,适用于增量更新、dto 合并等场景。
在使用 MapStruct 进行对象映射(尤其是 @MappingTarget 增量更新)时,一个常见需求是:仅当目标对象的某字段已有值(非 null)时,才跳过源字段的赋值;反之,若目标字段为 null,则允许从源对象映射新值。但需注意:题中原始诉求“if engine is null, I don't want to map it”实际语义易歧义——通常开发者真正意图是:“当目标 car.engine 已存在(非 null)时,不要用 carDto.device 覆盖它”,即“非空保护式映射”。
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) 表示“目标为空才映射”,符合多数增量更新场景(如部分字段补全);若需反向逻辑(目标非空才映射),只需调整条件即可。
⚠️ 注意事项与最佳实践
- ignore = true 是必须的:否则 MapStruct 会尝试自动映射 device → engine,覆盖 @AfterMapping 的逻辑;
- @AfterMapping 方法签名必须匹配:参数顺序需与主映射方法一致,且含 @MappingTarget 注解的目标对象;
- 避免副作用:@AfterMapping 中不应修改源对象(carDto),仅操作目标对象(car);
- 考虑 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;
}
}
此时 shouldMapEngine 将自动被 MapStruct 调用,仅当返回 true 时才执行 device → engine 映射。此方式更简洁、更贴近函数式表达,推荐新项目优先采用。
总之,MapStruct 的条件映射虽无开箱即用的 whenTargetNull 属性,但通过 @AfterMapping 或 @Condition,均可清晰、安全、可维护地实现业务所需的空值保护逻辑。











