关于MapStruct使用expression表达式的小坑

时间:2025-03-18 08:12:06

最近项目中使用了mapStruct进行对象属性拷贝,关于使用方式和原理不做赘述,可自行查找!

最近在使用中发现了mapStruct框架的一个小坑,在我们使用expression来指定处理source中的某个属性后设置到target对象的某个属性中的时,会出某种异常现象

如:

@Override
@Mappings({
      @Mapping(source = "leaveLesson", target = "hadLesson"),
      @Mapping(source = "quitPrice", target = "retireAmount"),
      @Mapping(source = "createdDate", target = "retireTime"),
      @Mapping(expression = "java(parseToRetireApplyStatus(()))", target = "retireApplyStatus")
})
RetireApplyRecordInfoVo convert(RetireApplyBillInfoRes applyBillInfoRes);

编译后的class:

    @Override
    public RetireApplyRecordInfoVo convert(RetireApplyBillInfoRes applyBillInfoRes) {
        if ( applyBillInfoRes == null ) {
            return null;
        }

        RetireApplyRecordInfoVo retireApplyRecordInfoVo = new RetireApplyRecordInfoVo();

        ( parseToRetireApplyStatus( () ) );
        ( () );
        ( () );
        ( () );
        ( () );
        ( () );

        ( parseToRetireApplyStatus(()) );

        return retireApplyRecordInfoVo;
    }

可以明显看到我只想处理 retireApplyStatus ,但是hadLesson 也经过了同样的方法处理。

 

于是做出猜想:是不是由于target类型与source类型两两一致才会这样?

做出如下修改,将parseToRetireApplyStatus方法的参数改为String类型并随便赋值一个String类型属性:

        @Override
        @Mappings({
                @Mapping(source = "leaveLesson", target = "hadLesson"),
                @Mapping(source = "quitPrice", target = "retireAmount"),
                @Mapping(source = "createdDate", target = "retireTime"),
                @Mapping(expression = "java(parseToRetireApplyStatus(()))", target = "retireApplyStatus")
        })
        RetireApplyRecordInfoVo convert(RetireApplyBillInfoRes applyBillInfoRes);

编译后:

    @Override
    public RetireApplyRecordInfoVo convert(RetireApplyBillInfoRes applyBillInfoRes) {
        if ( applyBillInfoRes == null ) {
            return null;
        }

        RetireApplyRecordInfoVo retireApplyRecordInfoVo = new RetireApplyRecordInfoVo();

        ( () );
        ( () );
        ( () );
        ( () );
        ( () );
        ( () );

        ( parseToRetireApplyStatus(()) );

        return retireApplyRecordInfoVo;
    }

明显这样就没有了对 leaveLesson->hadLesson 的类似处理。

那么这个问题应该如何解决呢?有两种方案,一是不适用expression,特殊字段在外面进行处理;二是,对发生冲突的字段leaveLesson也进行expression表达式处理,不过这种方式要冲突的字段有多少个了,视情况选择不同的处理方式吧!

我采用的后者:

        @Override
        @Mappings({
                @Mapping(expression = "java(())", target = "hadLesson"),
                @Mapping(source = "quitPrice", target = "retireAmount"),
                @Mapping(source = "createdDate", target = "retireTime"),
                // 注意当前Integer属性使用expression进行处理后,mapStruct自动生成代码中所有的Integer类型属性都会经过同样表达式处理,所以上面hadLesson字段也进行了expression指定
                @Mapping(expression = "java(parseToRetireApplyStatus(()))", target = "retireApplyStatus")
        })
        RetireApplyRecordInfoVo convert(RetireApplyBillInfoRes applyBillInfoRes);

编译后:

    @Override
    public RetireApplyRecordInfoVo convert(RetireApplyBillInfoRes applyBillInfoRes) {
        if ( applyBillInfoRes == null ) {
            return null;
        }

        RetireApplyRecordInfoVo retireApplyRecordInfoVo = new RetireApplyRecordInfoVo();

        ( () );
        ( () );
        ( () );
        ( () );
        ( () );

        ( () );
        ( parseToRetireApplyStatus(()) );

        return retireApplyRecordInfoVo;
    }

符合预期!具体原因待后续研究后补充!