欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Mapstruct 集合映射 从相同的源类映射扩展类异常问题—— Ambiguous mapping methods found for mapping collection element

程序员文章站 2022-03-08 15:57:41
...

问题1:

票证实体

public class Ticket {
  private long id;
  private String title;
  private Set<Comment> comments;

  // Getters and setters
}


票证DTO (父类)

public class TicketDTO {
  private long id;
  private String title;

  // Getters and setters
}


带有注释的票证DTO

public class TicketWithCommentsDTO extends TicketDTO {
  private List<CommentDTO> comments;


  // Getters and setters
}


票务映射器界面

@Mapper(uses= { CommentMapper.class })
public interface TicketMapper {
  TicketDTO mapToTicketDTO(Ticket ticket);

  List<TicketDTO> mapToTicketDTOList(Collection<Ticket> tickets); // Adding this method or the last method causes the error

  TicketWithCommentsDTO mapToTicketWithCommentsDTO(Ticket ticket);

  List<TicketWithCommentsDTO> MapToTicketWithCommentDTOList(Collection<Ticket> tickets); 
}


评论映射器界面

@Mapper
public interface CommentMapper {
  CommentDTO toCommentDTO(Comment comment);

  List<CommentDTO> toCommentDTOList(Collection<Comment> comments);
}


引发的错误:

 Ambiguous mapping methods found for mapping collection element to 
 dto.TicketDTO: dto.TicketDTO mapToTicketDTO(model.Ticket ticket), 
 dto.TicketWithCommentsDTO mapToTicketWithCommentsDTO(model.Ticket ticket).

最佳答案

这是一个简单的修复,确实是缺少的配置问题。缺少的是@IterableMapping批注。
 

@IterableMapping


elementTargetType设置为正确的类型。

正确的Mapper代码

@Mapper(uses = { CommentMapper.class })
public interface TicketMapper {
    TicketDTO mapToTicketDTO(Ticket ticket);

    @IterableMapping(elementTargetType = TicketDTO.class)
    List<TicketDTO> mapToTicketDTOList(Collection<Ticket> tickets);

    TicketWithCommentsDTO mapToTicketWithCommentsDTO(Ticket ticket);

    @IterableMapping(elementTargetType = TicketWithCommentsDTO.class)
    List<TicketWithCommentsDTO> mapToTicketWithCommentDTOList(Collection<Ticket> tickets);
}

========================

问题2: 多集合Mapping异常 BaseDO 为父类

   /**
     * dtoToDO
     *
     * @param dto
     * @return
     */
    ObjectControlDO dtoToDO(ObjectControlDto dto);

    /**
     * dtosToDOs
     *
     * @param dtos
     * @return
     */
    List<ObjectControlDO> dtosToDOs(List<ObjectControlDto> dtos);

    /**
     * dtoToDO
     *
     * @param dto
     * @return
     */
    BaseDO dtoToBaseDO(ObjectControlDto dto);

    /**
     * dtosToDOs
     *
     * @param dtos
     * @return
     */
    List<BaseDO> dtosToBaseDOs(List<ObjectControlDto> dtos);

解决方式

/**
     * dtoToDO
     *
     * @param dto
     * @return
     */
    @Named(value = "dtoToDO")
    ObjectControlDO dtoToDO(ObjectControlDto dto);

    /**
     * dtosToDOs
     *
     * @param dtos
     * @return
     */
    @IterableMapping(qualifiedByName = "dtoToDO")
    List<ObjectControlDO> dtosToDOs(List<ObjectControlDto> dtos);

    /**
     * dtoToDO
     *
     * @param dto
     * @return
     */
    @Named(value = "dtoToBaseDO")
    BaseDO dtoToBaseDO(ObjectControlDto dto);

    /**
     * dtosToDOs
     *
     * @param dtos
     * @return
     */
    @IterableMapping(qualifiedByName = "dtoToBaseDO")
    List<BaseDO> dtosToBaseDOs(List<ObjectControlDto> dtos);

3、 mapstruct-将父字段值传播给嵌套对象的集合

可以将值从父对象传播到嵌套对象的集合

DTO源类

class CarDTO {
  private String name;
  private long userId;
  private Set<WheelDto> wheels; 
};

class WheelDto {
  private String name;
}


目标实体类

class Car {
  private String name;
  private long userId;
  private Set<Wheel> wheels; 
};

class Wheel {
  private String name;
  private long lastUserId;
}


如您所见,我在WheelDto上没有lastUserId,因此我想在wheel集合中的每个对象上将CarDto的userId映射到WheelDto的lastUserId。

最佳答案

当前无法传递属性。但是,您可以通过@AfterMapping和/或@Context解决此问题。

汽车映射后更新车轮

但是,这意味着您需要对Wheel进行两次迭代。它看起来像

@Mapper
public interface CarMapper {

    Car map(CarDto carDto);

    @AfterMapping
    default void afterCarMapping(@MappingTarget Car car, CarDto carDto) {
        car.getWheels().forEach(wheel -> wheel.setLastUserId(carDto.getUserId()));
    }
}


在映射轮时传递@Context以便在映射期间具有状态

如果您只想通过Wheel进行一次迭代,则可以传递一个@Context对象,该对象将在映射汽车之前从CarDto获取userId,然后在之后的映射中将其设置在Wheel上。该映射器如下所示:

@Mapper
public interface CarMapper {

    Car map(CarDto carDto, @Context CarContext context);

    Wheel map(WheelDto wheelDto, @Context CarContext context);

}

public class CarContext {

    private String lastUserId;

    @BeforeMapping
    public void beforeCarMapping(CarDto carDto) {
        this.lastUserId = carDto.getUserId();
    }

    @AfterMapping
    public void afterWheelMapping(@MappingTarget Wheel wheel) {
        wheel.setLastUserId(lastUserId);
    }

}

CarContext将传递到车轮映射方法。

Mapstruct-从多个集合映射到单个集合

使用MapStruct,我的源对象中有两个集合,其中包含略有不同的对象。我想将这两个集合的对象映射为通用类型,然后将它们全部插入单个集合中。类似于以下内容:
 

List<UserNumber> listsToDtoList(List<PhoneNumber> phoneNumbers, List<FaxNumber> faxNumbers);

UserNumber phoneToPhoneDto(PhoneNumber phone);
UserNumber faxToPhoneDto(FaxNumber fax);


使用MapStruct做到这一点的最简单方法是什么?

最佳答案

因此,我将根据我的SourceObject进行映射(不写List<UserNumber> listsToDtoList(List<PhoneNumber> phoneNumbers, List<FaxNumber> faxNumbers);

所以大致如下:

@Mapping( target = "userNumbers", source = "phoneNumbers" )
Target map( Source source );

@AfterMapping // will be applied in the final part of the previous method
default void map ( Source source, @MappingTarget Target target ) {
 target.getUserNumbers().addAll(source.getFaxNumbers());
}

 

 参照:

https://mapstruct.org/documentation/stable/reference/html/

相关标签: java java