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

Prevent mapstruct from using the single object mapping function in list of object mapping function

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

B 处理的实体,其中引用了 A 的实体,被实现为简单的 Long 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 列表的函数对每个实体都使用了 entityToDto,导致对 A 的 n 个请求。之后,另一个 @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 函数而另一个版本不使用,以使 entityToDtoList 函数使用没有 @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;
    }

欢迎其他方法,我只觉得这个更自然。

提前致谢!

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

我可以给函数起一个名字,这样它们的工作方式就像它们具有特定的范围一样。 映射器界面变为:

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);
}

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

映射器摘要class:

    @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 class是:

@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;
    }
}

这正是我要找的。