【问题标题】:How to map extended DTO's from same source class如何映射来自同一源类的扩展 DTO
【发布时间】:2017-06-18 04:52:36
【问题描述】:

我已经开始使用 Mapstruct 将 JPA 实体映射到 DTO。对于基本实体,这很好用。

我的问题:一些实体有延迟加载的集合,包含额外的细节,我不想总是想要获取和映射。作为解决方案,我添加了一个基本超类,其中包含始终映射的所有字段,以及一个包含集合的子类。它们都代表相同的实体,因此它们使用相同的源类。

当我尝试创建一个包含从同一源映射到两种类型的方法的 Mapper 时,我得到一个模棱两可的映射方法错误,即使方法签名(至少返回类型)不同。 我会以错误的方式解决这个问题吗?我不能使用相同源的 DTO 的子类吗?

编辑: 万一这很重要,我正在使用 mapstruct-jdk8:1.1.0.Final

编辑 2: 下面的例子只是我头顶上的一个例子。当我实际使用代码时,它起作用了。事实证明,我的问题与示例中未包含的内容有关。当我添加映射票证集合的方法时,似乎发生了错误。这可能意味着问题与继承无关(直接?)。我可能缺少一些配置,但我不确定要查找什么。

简单示例:

票证实体

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
}

使用 cmets 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).

【问题讨论】:

  • 您能否向我们展示一下引发歧义方法错误的映射器?问题究竟出在哪里(错误或其他)可能会更清楚
  • @Filip,感谢您的回复!我已经编辑了我的问题,你能看看吗?如果您还需要什么,请告诉我。

标签: java mapstruct


【解决方案1】:

好吧,结果证明这是一个简单的修复,确实是缺少配置问题。缺少的是 @IterableMapping 注释。

一旦我将elementTargetType 设置为正确的类型,一切都会按预期工作。

正确的映射器代码

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

【讨论】:

  • 看来您已经找到了答案。我只想澄清一个小细节。 mapToTicketWithCommentDTOList 不需要elementTargetType。其原因是仅存在可以将Ticket 映射到TicketWithCommentsDTO 的方法(如果您的示例完整)。另一方面,有两种可能的方法可以将Ticket 映射到TicketDTOmapToTicketDTOmapToTicketWithCommentsDTO),模棱两可的错误消息来自这里。
  • @Filip 这很有道理(很尴尬,我没听懂,真的)。感谢您的澄清!
【解决方案2】:

您可以通过添加一些后映射方法来进行子类映射,如下所示:

@Mapper(...)
public interface SuperClassMapper {

SubClassMapper SUBCLASS_MAPPER_INSTANCE = Mappers.getMapper(SubClassMapper.class);

// Mappings entity to dto / dto to entity ...

@AfterMapping
default SuperClassDTO toSubClassDTO(SuperClass entity, @MappingTarget SuperClassDTO dto) 
{
    if (entity instanceof SubClass) {
        return SUBCLASS_MAPPER_INSTANCE.toDto((SubClass) entity);
    }
    return dto;
}

你当然应该已经定义了一个 SubClassMapper。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多