发布于2026-07-14 阅读(0)
扫一扫,手机访问
本文介绍如何在 MapStruct 中实现“仅当目标对象的某个字段不为 null 时,才将源字段映射过去”,避免覆盖已有值,适用于增量更新、DTO 合并等场景。
没错,这篇文章要讲的就是这个需求:在 MapStruct 的增量更新场景下,如何只让源字段赋值给目标对象中那些当前为 null 的字段,而如果目标字段已经有值,则保留不动。换句话说,就是“非空保护式映射”。
用例子说话:假设有一个 Car 对象,它的 engine 字段已经有点值了,现在从 CarDto 传进来一个 device 字段,你希望——只有当 car.engine 还是 null 的时候,才把 device 赋过去;如果 engine 已经非空,那就原封不动。这个逻辑在部分字段补全或合并更新中非常常见。
但 MapStruct 目前并没有一个 @Mapping(whenTargetNotNull = true) 这样开箱即用的注解。不过,别担心,通过组合策略,完全可以优雅地实现。
@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);Car 用了 @Data 或 @Setter,那 setEngine() 可以正常调用;如果类是不可变的,就得改用构造器或 Builder 模式;如果你的项目已经升级到 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,我们都能清晰、安全、可维护地实现业务所需的空值保护逻辑。关键是要想清楚“到底什么条件下才映射”,然后选一个顺手的方式去实现。
上一篇:Java 中 setDaemon 方法在单元测试环境下的使用策略
下一篇:JVM中Shenandoah收集器在多核处理器架构下对NUMA(Non-Uniform Memory Access)的适配
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8