商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > MapStruct 条件映射:当目标字段非空时才执行源字段赋值

MapStruct 条件映射:当目标字段非空时才执行源字段赋值

  发布于2026-07-14 阅读(0)

扫一扫,手机访问

本文介绍如何在 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,我们都能清晰、安全、可维护地实现业务所需的空值保护逻辑。关键是要想清楚“到底什么条件下才映射”,然后选一个顺手的方式去实现。

本文转载于:https://www.php.cn/faq/2814688.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注