1. Overview

MapStruct is a library that helps us to minimize boilerplate code when dealing with Java Beans mapping. It generates mappers using only provided interfaces.

In this tutorial, we’ll learn how to construct complex mappers built with simple ones and map nested structures.

2. Data

We’ll map the Article class to the DTO instance. Articles contain some simple fields but also contain the author field of the type Person. That field we’ll also map to the corresponding DTO. Here are the source classes:

@Getter
@Setter
public class Article {
    private int id;
    private String name;
    private Person author;
}
@Getter
@Setter
public class Person {  
    private String id;
    private String name;
}

And here are the target classes:

@Getter
@Setter
public class ArticleDTO {
    private int id;
    private String name;
    private PersonDTO author;
}
@Getter
@Setter
public class PersonDTO {
    private String id;
    private String name;
}

3. Defining Nested Mapper as Method

Let’s start with defining a simple mapper that will map our Article class:

@Mapper
public interface ArticleMapper {
   
    ArticleMapper INSTANCE = Mappers.getMapper(ArticleMapper.class);
    
    ArticleDTO articleToArticleDto(Article article);
}

This mapper will correctly map all literal fields in the source class but won’t map the author field because it doesn’t know how. Let’s define the PersonMapper interface:

@Mapper
public interface PersonMapper {
    
    PersonMapper INSTANCE = Mappers.getMapper(PersonMapper.class);
    
    PersonDTO personToPersonDTO(Person person);
}

Now the simplest thing we can do is to create a method in ArticleMapper defining a mapping from Person to PersonDTO:

default PersonDTO personToPersonDto(Person person) {
    return Mappers.getMapper(PersonMapper.class).personToPersonDTO(person);
}

MapStruct will automatically pick up this method and use it to map the author field.

4. Using Existing Mapper

While the solution above works, it’s a little cumbersome. Instead of defining a new method, we can point to mappers we want to use directly in the @Mapper annotation using the “uses” parameter:

@Mapper(uses = PersonMapper.class)
public interface ArticleUsingPersonMapper {
    
    ArticleUsingPersonMapper INSTANCE = Mappers.getMapper(ArticleUsingPersonMapper.class);
    
    ArticleDTO articleToArticleDto(Article article);
}

5. Conclusion

In this article, we learned how to use MapStruct mapper inside another mapper. As always, code examples can be found over on GitHub.

Course – LS (cat=Java)
announcement - icon

Get started with Spring Boot and with core Spring, through the Learn Spring course:

>> CHECK OUT THE COURSE

res – REST with Spring (eBook) (everywhere)