当前位置: 首页 > 知识库问答 >
问题:

防止mapstruct使用对象映射函数列表中的单个对象映射函数

欧阳元魁
2023-03-14

我有2个微服务:我们称它们为A和B。

由B处理的实体(其中引用了a的实体)被实现为简单的长id(例如groupId)

@Getter
@Setter
@NoArgsConstructor
@Entity
@Table(name = "WorkShifts")
@AllArgsConstructor
@Builder(toBuilder = true)
public class WorkShiftEntity extends BaseEntitySerial {
    @Column(name = "group_id")
    private Long groupId;
    private String description;
    @Column(name = "start_time")
    private Time startTime;
    @Column(name = "end_time")
    private Time endTime;
    @Column(name = "work_shift")
    private Integer workShift;
}

我想要实现的是使用mapstruct填充B(由A持有)的缺失组数据。到目前为止,我尝试使用@AfterMapping函数向a请求缺失的数据。我的映射器是:

@Mapper(componentModel = "spring", uses = LocalTimeMapper.class, builder = @Builder(disableBuilder = true), config = CommonMapperConfig.class)
public abstract class WorkShiftMapper extends BaseMapper implements IBaseMapper<WorkShiftEntity, WorkShiftDTO, Long>, LogSupport {
    @Autowired
    RestTemplate restTemplate;

    @Mapping(target = "groupId", source = "group.id")
    public abstract WorkShiftEntity dtoToEntity(WorkShiftDTO workShiftDTO);

    @AfterMapping
    public void afterEntityToDto(final WorkShiftEntity workShiftEntity, @MappingTarget final WorkShiftDTO workShiftDTO) {
        if (workShiftEntity == null) {
            return;
        }
        GroupDTO groupDTO = EcofinderUtils.getGroupDTO(restTemplate, workShiftEntity.getGroupId());

        try {
            GenericUtils.enhanceDTOForAttributeWithDTO(workShiftDTO, groupDTO, "group");
        } catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
            getLogger().error(e.getMessage());
        }
    }

    @AfterMapping
    public void afterEntityToDtoList(final List<WorkShiftEntity> workShiftEntity, @MappingTarget final List<WorkShiftDTO> workShiftDTO) {
        if (workShiftEntity == null || workShiftEntity.size() == 0) {
            return;
        }

        List<GroupDTO> groups = EcofinderUtils.getAllGroupDTOById(restTemplate, workShiftEntity.stream().map(WorkShiftEntity::getGroupId).distinct().toList());

        try {
            //Compile the resulting DTOs with the data got from the registry
            //Group
            GenericUtils.enhanceDTOListWithDataFromDTOJoiningEntities(workShiftDTO, groups, workShiftEntity, "group", "groupId");
        } catch (AppException | InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
            getLogger().error(e.getMessage());
        }
    }
}

给我映射功能的实现接口是:

public interface IBaseMapper<T extends BaseEntity<K>, D extends IBaseDTO<K>, K extends Serializable> {
    D entityToDto(T entity);

    List<D> entityToDtoList(List<T> entity);

    T dtoToEntity(D dto);
}

生成的代码的问题在于,将实体列表映射到DTO列表的函数对每个实体使用EntityToToTo,导致n个请求到a。之后,调用另一个@AfterMapping函数(仅在一个请求中收集所有ID并提取所有数据的函数,这是映射列表时唯一应该使用的函数)。

    //GENERATED CODE BY MAPSTRUCT
    @Override
    public WorkShiftDTO entityToDto(WorkShiftEntity workShiftEntity) {
        if ( workShiftEntity == null ) {
            return null;
        }

        WorkShiftDTO workShiftDTO = new WorkShiftDTO();

        workShiftDTO.setId( workShiftEntity.getId() );
        workShiftDTO.setDescription( workShiftEntity.getDescription() );
        workShiftDTO.setStartTime( localTimeMapper.map( workShiftEntity.getStartTime() ) );
        workShiftDTO.setEndTime( localTimeMapper.map( workShiftEntity.getEndTime() ) );
        workShiftDTO.setWorkShift( workShiftEntity.getWorkShift() );

        afterEntityToDto( workShiftEntity, workShiftDTO );

        return workShiftDTO;
    }
    @Override
    public List<WorkShiftDTO> entityToDtoList(List<WorkShiftEntity> entity) {
        //more code...
        List<WorkShiftDTO> list = new ArrayList<WorkShiftDTO>( entity.size() );
        for ( WorkShiftEntity workShiftEntity : entity ) {
            list.add( entityToDto( workShiftEntity ) );
        }

        afterEntityToDtoList( entity, list );

        return list;
    }

有没有办法让mapstruct实现entityToDto函数两次,其中一个版本使用@AfterMapping函数,另一个版本不使用,以便让EntityToTodToList函数使用不带@AfterMapping调用的版本?

类似于:

    @Override
    public WorkShiftDTO entityToDto(WorkShiftEntity workShiftEntity) {
        if ( workShiftEntity == null ) {
            return null;
        }

        WorkShiftDTO workShiftDTO = new WorkShiftDTO();

        workShiftDTO.setId( workShiftEntity.getId() );
        workShiftDTO.setDescription( workShiftEntity.getDescription() );
        workShiftDTO.setStartTime( localTimeMapper.map( workShiftEntity.getStartTime() ) );
        workShiftDTO.setEndTime( localTimeMapper.map( workShiftEntity.getEndTime() ) );
        workShiftDTO.setWorkShift( workShiftEntity.getWorkShift() );

        afterEntityToDto( workShiftEntity, workShiftDTO );

        return workShiftDTO;
    }
    public WorkShiftDTO entityToDtoNoAfter(WorkShiftEntity workShiftEntity) {
        if ( workShiftEntity == null ) {
            return null;
        }

        WorkShiftDTO workShiftDTO = new WorkShiftDTO();

        workShiftDTO.setId( workShiftEntity.getId() );
        workShiftDTO.setDescription( workShiftEntity.getDescription() );
        workShiftDTO.setStartTime( localTimeMapper.map( workShiftEntity.getStartTime() ) );
        workShiftDTO.setEndTime( localTimeMapper.map( workShiftEntity.getEndTime() ) );
        workShiftDTO.setWorkShift( workShiftEntity.getWorkShift() );

        return workShiftDTO;
    }
    @Override
    public List<WorkShiftDTO> entityToDtoList(List<WorkShiftEntity> entity) {
        //more code...
        List<WorkShiftDTO> list = new ArrayList<WorkShiftDTO>( entity.size() );
        for ( WorkShiftEntity workShiftEntity : entity ) {
            list.add( entityToDtoNoAfter( workShiftEntity ) );
        }

        afterEntityToDtoList( entity, list );

        return list;
    }

其他方法也很受欢迎,这种方法对我来说只是感觉更自然。

提前致谢!

共有1个答案

公西修文
2023-03-14

经过大约两天的深入研究和多次尝试,我想我已经找到了一个不错的解决方案。

我可以给这些函数一个名字,这样它们就像有一个特定的作用域一样工作。映射器界面变成:

public interface IBaseMapper<T extends BaseEntity<K>, D extends IBaseDTO<K>, K extends Serializable> {
    @BeanMapping(qualifiedByName = "EntityToDTO")
    D entityToDto(T entity);

    @Named("EntityToDTOList")
    public abstract D entityToDTOListEntity(T entity);

    @IterableMapping(qualifiedByName = "EntityToDTOList")
    List<D> entityToDtoList(List<T> entity);

    T dtoToEntity(D dto);
}

这样我就可以把我需要的所有功能组合在一起。

映射器抽象类:

    @Mapping(target = "groupId", source = "group.id")
    public abstract WorkShiftEntity dtoToEntity(WorkShiftDTO workShiftDTO);

    @AfterMapping
    @Named("EntityToDTO")
    public void afterEntityToDto(final WorkShiftEntity workShiftEntity, @MappingTarget final WorkShiftDTO workShiftDTO) {
        if (workShiftEntity == null) {
            return;
        }
        GroupDTO groupDTO = EcofinderUtils.getGroupDTO(restTemplate, workShiftEntity.getGroupId());

        try {
            GenericUtils.enhanceDTOForAttributeWithDTO(workShiftDTO, groupDTO, "group");
        } catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
            getLogger().error(e.getMessage());
        }
    }

    @AfterMapping
    @Named("EntityToDTOList")
    public void afterEntityToDtoList(final List<WorkShiftEntity> workShiftEntity, @MappingTarget final List<WorkShiftDTO> workShiftDTO) {
        if (workShiftEntity == null || workShiftEntity.size() == 0) {
            return;
        }

        List<GroupDTO> groups = EcofinderUtils.getAllGroupDTOById(restTemplate, workShiftEntity.stream().map(WorkShiftEntity::getGroupId).distinct().toList());

        try {
            //Compile the resulting DTOs with the data got from the registry
            //Group
            GenericUtils.enhanceDTOListWithDataFromDTOJoiningEntities(workShiftDTO, groups, workShiftEntity, "group", "groupId");
        } catch (AppException | InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
            getLogger().error(e.getMessage());
        }
    }

通过这样做,生成的Impl类是:

@Generated(
    value = "org.mapstruct.ap.MappingProcessor",
    date = "2022-05-20T15:08:38+0200",
    comments = "version: 1.4.2.Final, compiler: javac, environment: Java 17.0.1 (Oracle Corporation)"
)
@Component
public class WorkShiftMapperImpl extends WorkShiftMapper {

    @Autowired
    private LocalTimeMapper localTimeMapper;

    @Override
    public WorkShiftDTO entityToDto(WorkShiftEntity entity) {
        if ( entity == null ) {
            return null;
        }

        WorkShiftDTO workShiftDTO = new WorkShiftDTO();

        workShiftDTO.setId( entity.getId() );
        workShiftDTO.setDescription( entity.getDescription() );
        workShiftDTO.setStartTime( localTimeMapper.map( entity.getStartTime() ) );
        workShiftDTO.setEndTime( localTimeMapper.map( entity.getEndTime() ) );
        workShiftDTO.setWorkShift( entity.getWorkShift() );

        afterEntityToDto( entity, workShiftDTO );

        return workShiftDTO;
    }

    @Override
    public WorkShiftDTO entityToDTOListEntity(WorkShiftEntity entity) {
        if ( entity == null ) {
            return null;
        }

        WorkShiftDTO workShiftDTO = new WorkShiftDTO();

        workShiftDTO.setId( entity.getId() );
        workShiftDTO.setDescription( entity.getDescription() );
        workShiftDTO.setStartTime( localTimeMapper.map( entity.getStartTime() ) );
        workShiftDTO.setEndTime( localTimeMapper.map( entity.getEndTime() ) );
        workShiftDTO.setWorkShift( entity.getWorkShift() );

        return workShiftDTO;
    }

    @Override
    public List<WorkShiftDTO> entityToDtoList(List<WorkShiftEntity> entity) {
        if ( entity == null ) {
            return null;
        }

        List<WorkShiftDTO> list = new ArrayList<WorkShiftDTO>( entity.size() );
        for ( WorkShiftEntity workShiftEntity : entity ) {
            list.add( entityToDTOListEntity( workShiftEntity ) );
        }

        afterEntityToDtoList( entity, list );

        return list;
    }

    @Override
    public WorkShiftEntity dtoToEntity(WorkShiftDTO workShiftDTO) {
        if ( workShiftDTO == null ) {
            return null;
        }

        WorkShiftEntity workShiftEntity = new WorkShiftEntity();

        workShiftEntity.setGroupId( workShiftDTOGroupId( workShiftDTO ) );
        workShiftEntity.setId( workShiftDTO.getId() );
        workShiftEntity.setDescription( workShiftDTO.getDescription() );
        workShiftEntity.setStartTime( localTimeMapper.map( workShiftDTO.getStartTime() ) );
        workShiftEntity.setEndTime( localTimeMapper.map( workShiftDTO.getEndTime() ) );
        workShiftEntity.setWorkShift( workShiftDTO.getWorkShift() );

        return workShiftEntity;
    }

    private Long workShiftDTOGroupId(WorkShiftDTO workShiftDTO) {
        if ( workShiftDTO == null ) {
            return null;
        }
        GroupDTO group = workShiftDTO.getGroup();
        if ( group == null ) {
            return null;
        }
        Long id = group.getId();
        if ( id == null ) {
            return null;
        }
        return id;
    }
}

这正是我想要的。

 类似资料: