Mapstruct中@Mapping同时使用conditionQualifiedByName与expression的问题
问题背景
在使用MapStruct的@Mapping注解时,无法同时使用conditionQualifiedByName(条件校验)和expression(自定义表达式),条件会被忽略,导致空白参数传入后续方法引发异常。需要实现“先校验字段非null/空白,再执行映射逻辑”的需求,且复用已有的StaticUtil校验工具。
可行方案(推荐):使用conditionQualifiedByName + qualifiedByName组合
MapStruct允许在同一个@Mapping中同时使用条件校验和自定义映射方法(通过qualifiedByName指定),以此替代expression,完美解决冲突问题:
保留现有校验工具类
你的StaticUtil和UtilConditions注解无需修改,继续提供isNotBlank等校验逻辑。在Mapper中新增映射方法
把原expression中的逻辑抽成单独的映射方法,并添加@Named注解标记:@Named("mapCurrencyById") public Currency mapCurrencyById(String currencyName) { return currencyRepository.findById(currencyName) .orElseThrow(() -> new EntityNotFoundException(Currency.class, currencyName)); }修改@Mapping注解
移除expression参数,改用qualifiedByName指定上述映射方法,同时保留conditionQualifiedByName做前置校验:@Mapping(target = "name", conditionQualifiedByName = "isNotBlank") @Mapping(target = "firstName", conditionQualifiedByName = "isNotBlank") @Mapping(target = "rateCurrency", source = "rateCurrency", conditionQualifiedByName = "isNotBlank", qualifiedByName = "mapCurrencyById") public abstract Entity toEntity(EntityDto dto);
效果:MapStruct会先执行StaticUtil.isNotBlank(dto.getRateCurrency()),返回true时才调用mapCurrencyById完成映射;返回false时跳过映射,rateCurrency保持默认值(通常为null),彻底避免空白参数传入查询方法。
备选方案:将校验逻辑嵌入expression
如果不想新增映射方法,可直接将校验逻辑写入expression中,但可读性和复用性较差:
@Mapping(target = "rateCurrency", expression = "java(StringUtils.isNotBlank(dto.getRateCurrency()) ? getCurrencyById(dto.getRateCurrency()) : null)") public abstract Entity toEntity(EntityDto dto);
总结
优先选择conditionQualifiedByName + qualifiedByName的组合方案,既符合MapStruct的设计规范,又能复用已有校验逻辑,代码更清晰易维护。
内容的提问来源于stack exchange,提问作者tabool

