How to map entity and list of entities to a single DTO with nested list by using MapStruct?

user1134181 :

I need to convert some entity and list of entities to a single DTO by using MapStruct. This DTO includes nested list.

Let's say, I have the following persistence-backed POJO:

public class Entity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

    @Column(name = "name", nullable = false)
    private String name;

    // SKIPPED

    @OneToOne(mappedBy = "entity", cascade = CascadeType.ALL)
    private EntityMetadata entityMetadata;

}   

And some collection of this entities:

List<Entity> entities

DTO is presented below:

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class ScreenDocumentDto { // dto
    private Long id;
    private String name;
    List<SomeLinkDto> someLinks;
}

And nested DTO:

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class SomeLinkDto {
    private Long id;
    private ZonedDateTime someDate;
}

All the fields except the someLinks list I need to map from entity:

dto.setId(entity.getId());
dto.setName(entity.getName());
// SKIPPED

Nested list I populate as follows:

List<SomeLinkDto> someLinks = new ArrayList<>(entities.size());
for (Entity entity  : entities) {
    someLinks.add(SomeLinkDto.builder().id(entity.getId())
        .someDate(entity.getEntityMetadata().getSomeDate()).build());
}

The result involves a lot of manually transformations:

@Mapper(componentModel = "spring")
public interface ScreenDocumentMapper extends BaseMapper<Entity, ScreenDocumentDto> {
    default ScreenDocumentDto toScreenDocumentDto(List<Entity> entities, Entity entity) {
        ScreenDocumentDto dto = new ScreenDocumentDto();
        List<SomeLinkDto> someLinks = new ArrayList<>(entities.size());
        for (Entity entity  : entities) {
            someLinks.add(SomeLinkDto.builder().id(entity.getId())
                .someDate(entity.getEntityMetadata().getSomeDate()).build());
        }

        dto.setId(entity.getId());
        dto.setName(entity.getName());
        ...
        dto.setSomeLinks(someLinks);

        return dto;
    }

    // SKIPPED

Is there a way to do the same job by using features of MapStruct? Like that:

@Mapper(componentModel = "spring")
public interface ScreenDocumentMapper extends BaseMapper<Entity, ScreenDocumentDto> {
    @Mappings({
        @Mapping(source = "...", target = "..."),
            ...
    })
    ScreenDocumentDto toDto(Entity entity);
}
Filip :

You can achieve the custom toScreenDocumentDto method with MapStruct by using multiple source parameters.

For example

@Mapper(componentModel = "spring")
public interface ScreenDocumentMapper extends BaseMapper<Entity, ScreenDocumentDto> {

    @Mapping(source = "entities", target = "someLinks")
    ScreenDocumentDto toDto(Entity entity, List<Entity> entities);

    @Mapping(source = "entityMetadata.someDate", target = "someDate")
    SomeLinkDto toLinkDto(Entity entity);
}

In case the Entity has the links as a property you can do:

@Mapper(componentModel = "spring")
public interface ScreenDocumentMapper extends BaseMapper<Entity, ScreenDocumentDto> {

    @Mapping(source = "links", target = "someLinks")
    ScreenDocumentDto toDto(Entity entity);

    @Mapping(source = "entityMetadata.someDate", target = "someDate")
    SomeLinkDto toLinkDto(Entity entity);
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=161752&siteId=1