I've started using Mapstruct to map JPA entities to DTO's. For basic entities, this works great.
My problem: Some entities have lazy loaded collections, containing additional details, that I don't want always want to fetch and map. As a solution I've added a basic superclass with all fields that are always mapped, and a subclass containing the collections. They both represent the same entity, so they use the same source class.
When I try to create a Mapper containing methods to map to both types from the same source, I get an ambiguous mapping methods error, even though the method signature (at least the return type) is different. Am I going about this the wrong way? Can't I use subclasses for DTO's using the same source?
Edit: In case it matters, I'm using mapstruct-jdk8:1.1.0.Final
Edit 2: The example below was just an example, on the top of my head. When I've actually used the code, it worked. It turns out my issue is with something that wasn't included in the example. It appears that the error occurs when I add a method for mapping a Collection of Tickets. This probably means the issue is not (directly?) related with inheritance. I'm probably missing some configuration, but I'm not sure what to look for.
Simple example:
Ticket entity
public class Ticket {
private long id;
private String title;
private Set<Comment> comments;
// Getters and setters
}
Ticket DTO
public class TicketDTO {
private long id;
private String title;
// Getters and setters
}
Ticket with comments DTO
public class TicketWithCommentsDTO extends TicketDTO {
private List<CommentDTO> comments;
// Getters and setters
}
Ticket Mapper interface
@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);
}
Comment Mapper interface
@Mapper
public interface CommentMapper {
CommentDTO toCommentDTO(Comment comment);
List<CommentDTO> toCommentDTOList(Collection<Comment> comments);
}
The error thrown:
Ambiguous mapping methods found for mapping collection element to
dto.TicketDTO: dto.TicketDTO mapToTicketDTO(model.Ticket ticket),
dto.TicketWithCommentsDTO mapToTicketWithCommentsDTO(model.Ticket ticket).
Well, this turned out to be a simple fix, it was indeed a missing configuration issue. What was missing was the @IterableMapping
annotation.
Once I set the elementTargetType
to the correct types, everything worked as expected.
The correct Mapper code
@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);
}