You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Mapstruct中@Mapping同时使用conditionQualifiedByName与expression的问题

MapStruct 条件校验与自定义映射共存的解决方案

问题背景

在使用MapStruct的@Mapping注解时,无法同时使用conditionQualifiedByName(条件校验)和expression(自定义表达式),条件会被忽略,导致空白参数传入后续方法引发异常。需要实现“先校验字段非null/空白,再执行映射逻辑”的需求,且复用已有的StaticUtil校验工具。

可行方案(推荐):使用conditionQualifiedByName + qualifiedByName组合

MapStruct允许在同一个@Mapping中同时使用条件校验和自定义映射方法(通过qualifiedByName指定),以此替代expression,完美解决冲突问题:

  1. 保留现有校验工具类
    你的StaticUtil和UtilConditions注解无需修改,继续提供isNotBlank等校验逻辑。

  2. 在Mapper中新增映射方法
    把原expression中的逻辑抽成单独的映射方法,并添加@Named注解标记:

    @Named("mapCurrencyById")
    public Currency mapCurrencyById(String currencyName) {
        return currencyRepository.findById(currencyName)
            .orElseThrow(() -> new EntityNotFoundException(Currency.class, currencyName));
    }
    
  3. 修改@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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 12:52:52