为了账号安全,请及时绑定邮箱和手机立即绑定

MapStruct Mapper 作为 Spring Framework 可以惯用使用吗?

MapStruct Mapper 作为 Spring Framework 可以惯用使用吗?

红颜莎娜 2023-08-23 14:33:38
我想将MapStruct映射器与 Spring 的Conversion model结合起来。所以我将每个Mapper接口声明为 Spring 的扩展Converter:@Mapperpublic interface CarMapper extends Converter<Car, CarDto> {        @Override    CarDto convert(Car car);    }然后我可以通过注入标准来使用映射器 bean ConversionService:class CarWarehouse {    @Autowired    private ConversionService conversionService;    ...    public CarDto getCarInformation(Car car) {        return conversionService.convert(car, CarDto.class);    }}这很好用,但我想知道是否有一种方法可以避免通过属性直接将一些映射器注入其他映射器uses。我想做的是告诉映射器use雇用ConversionService另一个映射器。但是,由于ConversionServicesconvert方法与 MapStruct 的映射方法标准模式不匹配,因此代码生成插件在查找子映射时无法识别它可以使用该服务。基本上,我想做的是写@Mapper(uses=ConversionService.class)public interface ParentMapper extends Converter<Parent, ParentDto>代替@Mapper(uses={ChildMapper1.class, ChildMapper2.class, ChildMapper3.class})public interface ParentMapper extends Converter<Parent, ParentDto>有办法实现这一点吗?编辑既然有人问过,假设我有一个CarMapper如上所述的定义,其类型Car和分别具有类型和的CarDto属性。然后我希望能够像这样定义另一个映射器:wheelWheelWheelDto@Mapperpublic interface WheelMapper extends Converter<Wheel, WheelDto> {        @Override    WheelDto convert(Wheel wheel);    }现在,我必须显式添加此映射器:@Mapper(uses = WheelMapper.class)public interface CarMapper extends Converter<Car, CarDto>然后,这将为生成的类型提供CarMapperImpl一个@Autowired成员WheelMapper,该成员将被调用以映射属性wheel。然而,我想要的是生成的代码看起来有点像这样:@Componentpublic class CarMapperImpl implements CarMapper {    @Autowired    private ConversionService conversionService;    @Override    public CarDto convert(Car car) {        CarDto carDto = new CarDto();        carDto.setWheel(conversionService.convert(car.getWheel(), WheelDto.class);        return carDto;    }}
查看完整描述

2 回答

?
忽然笑

TA贡献1806条经验 获得超5个赞

自从我提出这个问题以来已经一年多了,但现在我们已经在 MapStruct 项目本身中找到了答案 - MapStruct Spring Extensions项目。

项目中提供了一个示例作为示例CarMapper


查看完整回答
反对 回复 2023-08-23
?
森栏

TA贡献1810条经验 获得超5个赞

您可以完全跳过传递 a WheelMapper,当您只有 a 时,CarMapper生成的也将包含映射<->CarMapperImpl的逻辑。无需将任何内容传递给,使您的问题过时。WheelWheelDtouses


carDto.setWheel( wheelToWheelDto( car.getWheel() ) );

用类似的方法;


protected WheelDto wheelToWheelDto(Wheel wheel) {

    if ( wheel == null ) {

        return null;

    }


    WheelDto wheelDto = new WheelDto();


    wheelDto.setName( wheel.getName() );


    return wheelDto;

}

我确实尝试过实现ConversionServicethrough的智能注入MapStruct,但我认为这是不可能的。您需要来自的支持MapStruct才能实现这样的壮举。它甚至不考虑注入ConversionService。也许已经实现并使用的自定义通用映射器ConversionService可能会起作用,但我无法做到这一点!虽然我没有看到任何原因,因为MapStruct已经从父映射器创建了所有必要的较小映射器......


查看完整回答
反对 回复 2023-08-23
?
冉冉说

TA贡献1877条经验 获得超1个赞

坦率地说,我怀疑您是否可以ConversionService通过 . 实现自动连接到生成的映射器MapStruct。您在问题中描述的方式(通过注释属性连接各个映射器)可能是开箱即用的uses最佳方式。MapStruct


但是,如果您绝对需要使用某些 DTO 执行转换ConversionService(例如,如果您有一些旧版转换器,但您不想重构映射器),则可以使用解决方法。基本上,您可以使用静态工厂的组合来获取映射器接口中的Mappers.getMapper实例ConversionService和方法,以使用实例:defaultConversionService


@Mapper(componentModel = "spring")

public interface CarMapper extends Converter<Car, CarDto> {


    ConversionService CONVERSION_SERVICE = Mappers.getMapper(ConversionService.class);


    @Override

    default CarDto convert(Car car) {

        if (car == null) {

            return null;

        }


        CarDto carDto = new CarDto();


        carDto.setEngine(CONVERSION_SERVICE.convert(car.getEngine(), EngineDto.class));

        carDto.setWheel(CONVERSION_SERVICE.convert(car.getWheel(), WheelDto.class));


        return carDto;

    }

}

注意:如您所见,解决方法需要编写CarMapper代码。因此,在我看来,带有注释属性的解决方案uses是更干净的方法。例如,通过定义以下接口,您可以获得几乎相同的结果:


@Mapper(componentModel = "spring", 

        uses = {EngineMapper.class, WheelMapper.class}, 

        injectionStrategy = InjectionStrategy.CONSTRUCTOR)

public interface CarMapper extends Converter<Car, CarDto> {

    @Override

    CarDto convert(Car car);

生成的映射器:


@Component

public class CarMapperImpl implements CarMapper {


    private final EngineMapper engineMapper;

    private final WheelMapper wheelMapper;


    @Autowired

    public CarMapperImpl(EngineMapper engineMapper, WheelMapper wheelMapper) {


        this.engineMapper = engineMapper;

        this.wheelMapper = wheelMapper;

    }


    @Override

    public CarDto convert(Car car) {

        if (car == null) {

            return null;

        }


        CarDto carDto = new CarDto();


        carDto.setEngine(engineMapper.convert(car.getEngine()));

        carDto.setWheel(wheelMapper.convert(car.getWheel()));


        return carDto;

    }

}


查看完整回答
反对 回复 2023-08-23
  • 2 回答
  • 0 关注
  • 140 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信