MapStruct配置:DTO所有属性为空时返回null而非空对象
问题背景
你现在有一个映射数据库视图的扁平实体类VwPlanningAmlControl,需要转成带嵌套UserPlanningDTO的PlanningAmlControlDTO。目前遇到的问题是:当映射UserPlanningDTO用到的所有源字段全为null时,MapStruct会返回一个所有属性为null的空UserPlanningDTO对象,而期望此时直接返回null。
现有代码
源实体类(核心关联字段展示)
public class VwPlanningAmlControl { // 其他业务字段省略 // confirmedBy关联字段 private Integer confirmedbyid; private String confirmedbyfirstname; private String confirmedbylastname; // rejectedBy关联字段 private Integer rejectedbyid; private String rejectedbyfirstname; private String rejectedbylastname; // createdBy关联字段 private Integer createdbyid; private String createdbyfirstname; private String createdbylastname; // modifiedBy关联字段 private Integer updatedbyid; private String updatedbyfirstname; private String updatedbylastname; }
目标DTO类
public class UserPlanningDTO { private Integer id; private String firstName; private String lastName; } public class PlanningAmlControlDTO extends EventAmlControlDTO { // 其他业务字段省略 private UserPlanningDTO confirmedBy; private UserPlanningDTO rejectedBy; private UserPlanningDTO createdBy; private UserPlanningDTO modifiedBy; }
现有映射配置
@Mapping(target = "id", source = "controlid") // 其他普通业务字段映射省略 @Mapping(target = "confirmedBy.id", source = "confirmedbyid") @Mapping(target = "confirmedBy.firstName", source = "confirmedbyfirstname") @Mapping(target = "confirmedBy.lastName", source = "confirmedbylastname") @Mapping(target = "rejectedBy.id", source = "rejectedbyid") @Mapping(target = "rejectedBy.firstName", source = "rejectedbyfirstname") @Mapping(target = "rejectedBy.lastName", source = "rejectedbylastname") @Mapping(target = "createdBy.id", source = "createdbyid") @Mapping(target = "createdBy.firstName", source = "createdbyfirstname") @Mapping(target = "createdBy.lastName", source = "createdbylastname") @Mapping(target = "modifiedBy.id", source = "updatedbyid") @Mapping(target = "modifiedBy.firstName", source = "updatedbyfirstname") @Mapping(target = "modifiedBy.lastName", source = "updatedbylastname") PlanningAmlControlDTO toDto(VwPlanningAmlControl planningAmlControl);
解决方案
MapStruct默认只要源对象不为null,就会实例化嵌套的目标对象,不会自动检查所有映射属性是否全为空。我们可以通过自定义映射条件实现需求,推荐使用MapStruct提供的@Condition注解方案,优雅且易维护:
步骤1:自定义条件判断类
public class UserMappingCondition { @Condition public boolean needBuildUserDTO(VwPlanningAmlControl source, @TargetProperty String targetProperty) { switch (targetProperty) { case "confirmedBy": // 只要有一个关联字段不为空就需要构建DTO return source.getConfirmedbyid() != null || source.getConfirmedbyfirstname() != null || source.getConfirmedbylastname() != null; case "rejectedBy": return source.getRejectedbyid() != null || source.getRejectedbyfirstname() != null || source.getRejectedbylastname() != null; case "createdBy": return source.getCreatedbyid() != null || source.getCreatedbyfirstname() != null || source.getCreatedbylastname() != null; case "modifiedBy": return source.getUpdatedbyid() != null || source.getUpdatedbyfirstname() != null || source.getUpdatedbylastname() != null; default: return true; } } }
步骤2:在Mapper中引入条件配置
@Mapper( uses = UserMappingCondition.class, nullValueMappingStrategy = NullValueMappingStrategy.RETURN_NULL ) public interface PlanningAmlControlMapper { // 原有所有@Mapping配置保持不变即可 PlanningAmlControlDTO toDto(VwPlanningAmlControl planningAmlControl); }
配置后MapStruct生成代码时,会先调用条件方法判断是否需要构建嵌套的UserPlanningDTO,如果所有关联字段全为null,就会直接给属性赋值为null,不会再实例化空对象。
其他可选方案(不推荐)
如果不想额外写条件类,也可以直接在@Mapping中用expression硬编码判断,缺点是代码冗余维护性差:
@Mapping( target = "confirmedBy", expression = "java( planningAmlControl.getConfirmedbyid() == null && planningAmlControl.getConfirmedbyfirstname() == null && planningAmlControl.getConfirmedbylastname() == null ? null : new UserPlanningDTO(planningAmlControl.getConfirmedbyid(), planningAmlControl.getConfirmedbyfirstname(), planningAmlControl.getConfirmedbylastname()) )" ) // 其他三个嵌套字段同理配置即可
内容的提问来源于stack exchange,提问作者usr-local-ΕΨΗΕΛΩΝ
相关产品推荐
相关产品推荐

