如何从同一来源映射扩展 DTO class
How to map extended DTO's from same source class
我已经开始使用 Mapstruct 将 JPA 实体映射到 DTO。对于基本实体,这很有效。
我的问题:一些实体有延迟加载的集合,包含额外的细节,我不想总是想要获取和映射。作为解决方案,我添加了一个基本的 superclass,其中包含始终映射的所有字段,以及一个包含集合的 subclass。它们都代表相同的实体,因此它们使用相同的来源 class.
当我尝试创建一个 Mapper,其中包含从同一来源映射到两种类型的方法时,我收到一个映射方法不明确的错误,即使方法签名(至少 return 类型)不同.
我会以错误的方式解决这个问题吗?我不能对使用相同来源的 DTO 使用 subclasses 吗?
编辑:
以防万一,我正在使用 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
}
带有注释 DTO 的票证
public class TicketWithCommentsDTO extends TicketDTO {
private List<CommentDTO> comments;
// Getters and setters
}
Ticket Mapper 界面
@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
注释。
一旦我将 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);
}
你可以通过添加一些像下面这样的后映射方法来做子类映射:
@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。
我已经开始使用 Mapstruct 将 JPA 实体映射到 DTO。对于基本实体,这很有效。
我的问题:一些实体有延迟加载的集合,包含额外的细节,我不想总是想要获取和映射。作为解决方案,我添加了一个基本的 superclass,其中包含始终映射的所有字段,以及一个包含集合的 subclass。它们都代表相同的实体,因此它们使用相同的来源 class.
当我尝试创建一个 Mapper,其中包含从同一来源映射到两种类型的方法时,我收到一个映射方法不明确的错误,即使方法签名(至少 return 类型)不同. 我会以错误的方式解决这个问题吗?我不能对使用相同来源的 DTO 使用 subclasses 吗?
编辑: 以防万一,我正在使用 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
}
带有注释 DTO 的票证
public class TicketWithCommentsDTO extends TicketDTO {
private List<CommentDTO> comments;
// Getters and setters
}
Ticket Mapper 界面
@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
注释。
一旦我将 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);
}
你可以通过添加一些像下面这样的后映射方法来做子类映射:
@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。