MapStruct 条件映射:若目标字段非空则执行源字段赋值

作者:袖梨 2026-07-27

本文介绍如何在 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 + 显式判空逻辑

@Mapperpublic 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 实现更声明式的条件映射:

@Mapperpublic 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,均可清晰、安全、可维护地实现业务所需的空值保护逻辑。

相关文章

精彩推荐