Skip to content
Dev Discovers

MapStruct: Simplify Java Object Mapping

java3 min read

MapStruct is a code generator that generates mapping code at compile-time. It uses annotations to generate mapping code between Java beans. It generates code that performs mappings between source and target objects, including nested mappings, mappings between collections, and other advanced mapping scenarios.

It allows developers to write less boilerplate code while ensuring type-safe, null-safe, and easily maintainable mapping between different objects.

The MapStruct code generator can be used to generate mapping code for a variety of use cases, including:

  • Mapping DTOs to entity classes
  • Mapping between different versions of an API
  • Converting data between different data models
  • Implementing the Adapter Pattern

How MapStruct Works

MapStruct uses a combination of code generation and runtime mapping to generate mappings between different objects. It generates code that performs the mapping between source and target objects, eliminating the need for developers to write boilerplate code for mapping between objects.

To use MapStruct, developers need to define the mapping interfaces using annotations. These mapping interfaces are then compiled to generate the mapping code. The generated mapping code is then used at runtime to perform the mappings between objects.

Code Examples

To get started with MapStruct, you first need to include the MapStruct dependency in your Maven or Gradle build file. Once you have done that, you can start creating mapping interfaces.

Mapping Between DTO and Entity

Here is an example of a simple mapping interface that maps between two Person objects:

public interface PersonMapper {
PersonMapper INSTANCE = Mappers.getMapper(PersonMapper.class);
PersonDTO personToPersonDTO(Person person);
Person personDTOToPerson(PersonDTO personDTO);

In this example, we have defined a simple mapping interface that maps between a Person object and a PersonDTO object. The @Mapper annotation tells MapStruct that this is a mapping interface that needs to be compiled to generate mapping code.

We have also defined two mapping methods, personToPersonDTO and personDTOToPerson, that perform the mapping between the Person and PersonDTO objects.

The INSTANCE field is a static field that provides an instance of the generated mapping code. It is a good practice to define this field in all mapping interfaces.

Here is an example of how you can use the PersonMapper interface to map between Person and PersonDTO objects:

Person person = new Person("John", "Doe");
PersonDTO personDTO = PersonMapper.INSTANCE.personToPersonDTO(person);

In this example, we create a new Person object and then use the personToPersonDTO method of the PersonMapper interface to map the Person object to a PersonDTO object.

Mapping Between Different Property Names

Suppose we have two classes, Person and User, with the following properties:

public class Person {
private String name;
private int age;
// constructors, getters, setters
public class User {
private String fullName;
private int userAge;
// constructors, getters, setters

To map between these two classes, we can create a MapStruct mapper interface with the appropriate mapping annotations:

public interface PersonUserMapper {
PersonUserMapper INSTANCE = Mappers.getMapper(PersonUserMapper.class);
@Mapping(source = "name", target = "fullName")
@Mapping(source = "age", target = "userAge")
User personToUser(Person person);

In the mapper interface above, we are defining a method personToUser that maps a Person object to a User object. We are using the @Mapping annotation to specify which property from the source object (Person) should be mapped to which property of the target object (User). Here, we are mapping the name property of Person to the fullName property of User, and the age property of Person to the userAge property of User.

To use the mapper, we can simply call the personToUser method on the INSTANCE field of the PersonUserMapper interface:

Person person = new Person("John Doe", 30);
User user = PersonUserMapper.INSTANCE.personToUser(person);

This will create a new User object with the fullName and userAge properties mapped from the corresponding properties of the Person object.

Final Thoughts

In general, if you have complex mapping requirements or if you want to ensure that your mapping code is type-safe and maintainable, MapStruct is a good choice. However, if you have simple mapping requirements or if you are working with a small project, you may not need to use MapStruct.

© 2023 by Dev Discovers. All rights reserved.
Theme by LekoArts