Mapping Entities to DTOs and vice versa in Java

Samuel Catalano
The Fresh Writes
Published in
5 min readJan 19, 2024

In Java, entities and DTOs are two different types of classes often used together. Entities are used to represent data in the database, while DTOs are used to represent data that is sent to or received from a client.

To map data from an entity to a DTO, you need to define a mapping between the attributes of the two classes. This can be done manually or automatically.

Manual mapping

Manual mapping is the simplest way to map entities to DTOs. In this approach, you write code to copy the values from an entity's attributes to a DTO's attributes.

For example, the following code maps the attributes of a Customer entity to the attributes of a CustomerDTO:

public CustomerDto toDto(Customer customer) {
CustomerDto dto = new CustomerDto();
dto.setName(customer.getName());
dto.setCpf(customer.getCpf());
dto.setDateOfBirth(customer.getDateOfBirth());
return dto;
}

This approach is simple and flexible, but it can be repetitive and error-prone, especially for complex entities or with many mappings.

Automatic mapping

Automatic mapping is a more efficient and reliable way to map entities to DTOs. In this approach, you use a framework or library to generate the mapping code automatically.

One popular library for automatic mapping is MapStruct: MapStruct (https://mapstruct.org/), which uses a Domain-Specific Language (DSL) to define the mapping rules.

For example, the following code defines the mapping rules to map the attributes of a Customer entity to the attributes of a CustomerDTO:

@Mapper
public interface CustomerMapper {

CustomerDto toDto(Customer customer);

}

The above code defines a method toDto() that takes an Customer entity as input and returns a CustomerDTO as output. MapStruct uses the names of the methods to determine the mapping between the attributes of the two classes.

MapStruct can also be used to map values from DTO to entity. For example, the following code defines the mapping rules to map the attributes of a CustomerDTO to the attributes of a Customer:

@Mapper
public interface CustomerMapper {

Customer fromDto(CustomerDto dto);

}

There is also a powerful library called ModelMapper that simplifies the object mapping process and provides a lot of flexibility in customizing the mapping behaviour.

To start using ModelMapper in your Java project, you need to add the ModelMapper library to your project. If you are using Maven, add the following dependency to your project’s pom.xml file:

<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>2.4.2</version>
</dependency>

If you are using Gradle, add the following to your build.gradle file:

implementation 'org.modelmapper:modelmapper:2.4.2'

After adding the ModelMapper library to your project, you can start using it to map between two objects with different structures.

Let’s say you have two objects with different structures, and you want to map data between them. Here’s an example:

public class User {
private String name;
private int age;

// constructor, getters, and setters
}

public class UserDTO {
private String fullName;
private int userAge;

// constructor, getters, and setters
}

public class Main {
public static void main(String[] args) {
User user = new User("John", 30);
ModelMapper modelMapper = new ModelMapper();
UserDTO userDTO = modelMapper.map(user, UserDTO.class);
System.out.println(userDTO.getFullName()); // Output: John
System.out.println(userDTO.getUserAge()); // Output: 30
}
}

In the above example, we have two objects User and UserDTO with different structures. The User object has fields name and age, while the UserDTO object has fields fullName and userAge. We use the ModelMapper instance to map the User object to UserDTO. The map() method takes two arguments: the source object and the destination object class.

When we run the main method, the output will be John and 30, which indicates that the mapping was successful.

For complete guidance on how to use and customize the ModelMapper, you can run through this article: http://bit.ly/4b4b5sz

So, which approach to choose?

The best approach to map entities to DTOs depends on several factors. In general, manual mapping is a good option for simple classes or with few mappings. Automatic mapping is a good option for complex classes or with many mappings.

Here are some considerations for choosing an approach:

  • The complexity of the classes involved: Complex classes with many attributes can make manual mapping repetitive and error-prone. Automatic mapping can be a good option for these classes.
  • Amount of mappings needed: Classes with many mappings can make manual mapping difficult to maintain. Automatic mapping can be a good option for these classes.
  • Need for customization: Manual mapping allows you to customize the mapping as needed. Automatic mapping can be more restrictive.

Ultimately, the best way to map entities to DTOs is the one that meets the specific needs of your application.

Additional considerations

In addition to the factors mentioned above, there are a few other considerations to keep in mind when mapping entities to DTOs:

  • Data types: Make sure that the data types of the attributes in the two classes are compatible.
  • Null values: Consider how you want to handle null values.
  • Collections: If either class has a collection of attributes, you need to define a mapping for each element in the collection.

By following these considerations, you can ensure that your mapping code is accurate and efficient.

Conclusion

MapStruct and ModelMapper offer convenient and efficient solutions for mapping entities to DTOs and vice versa in Java projects. By adopting these libraries, developers can significantly reduce boilerplate code, enhance code maintainability, and ensure type-safe mappings. Incorporating MapStruct or ModelMapper into your projects simplifies the mapping process, allowing you to focus on building robust and scalable applications.

Happy coding ;)

Also refer to the following articles

--

--

Samuel Catalano
The Fresh Writes

Samuel is a Software Engineer from Brazil with main interests in Java, Spring Boot, Quarkus, Microservices, Docker, Databases, Kubernetes, and Clean Code