When building a Spring Boot application, you often need to convert between DTOs (Data Transfer
Objects) and Entities. Doing this manually can make your code long, repetitive, and hard to maintain.
That’s where ModelMapper becomes incredibly useful.
ModelMapper automatically maps one object to another when the field names and types match, and it
also allows custom configurations when they don’t.
In this article, we’ll explore:
- Why do we use ModelMapper?
- How to add it to a Spring Boot project.
- Real-world use case.
- Example entity, DTO, and mapping logic.
- Advanced custom mappings.
Why Use ModelMapper?
- Reduces repetitive setter/getter conversions.
- Handles nested structures.
- Easy to customize.
- Reduces boilerplate in controllers and services.
- Makes code cleaner and more maintainable.
Add ModelMapper to Your Spring Boot Project
- Add the dependency in your pom.xml:
org.modelmapper
modelmapper
3.2.0
- If using gradle, in build.gradle file:
implementation 'org.modelmapper:modelmapper:3.2.4'
Then register it as a Spring Bean:
@Configuration
public class AppConfig {
@Bean
public ModelMapper modelMapper() {
return new ModelMapper();
}
}
Real World Example: Customer Management
Customer Entity:
@Entity
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String fullName;
private String email;
private String phone;
private String city;
private LocalDate registeredDate;
}
Notice the DTO does not contain registeredDate.
This is common because DTOs send only what the client needs.
public class CustomerDTO {
private Long id;
private String fullName;
private String email;
private String phone;
private String city;
}
Mapping Entity ↔ DTO Using ModelMapper
Convert Entity to DTO
public CustomerDTO convertToDto(Customer customer) {
return modelMapper.map(customer, CustomerDTO.class);
}
Convert DTO to Entity
public Customer convertToEntity(CustomerDTO dto) {
return modelMapper.map(dto, Customer.class);
}
That’s all ModelMapper needs when field names match.
Service Layer Example (Real API Use Case)
import org.modelmapper.ModelMapper;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
@Service
public class CustomerService {
private final CustomerRepository customerRepository;
private final ModelMapper modelMapper;
// Constructor Injection
public CustomerService(CustomerRepository customerRepository, ModelMapper modelMapper) {
this.customerRepository = customerRepository;
this.modelMapper = modelMapper;
}
public CustomerDTO createCustomer(CustomerDTO dto) {
Customer customer = modelMapper.map(dto, Customer.class);
customer.setRegisteredDate(LocalDate.now());
customer = customerRepository.save(customer);
return modelMapper.map(customer, CustomerDTO.class);
}
public CustomerDTO getCustomer(Long id) {
Customer customer = customerRepository.findById(id)
.orElseThrow(() -> new RuntimeException("Customer not found"));
return modelMapper.map(customer, CustomerDTO.class);
}
}
Advanced Case: When Field Names Do NOT Match
Let’s say your DTO contains fields that are different from the Entity.
DTO Example
public class CustomerDTO {
private String name;
private String email;
}
Entity Example
public class Customer {
private String fullName;
}
Field name mismatch: name → fullName.
Custom Mapping
ModelMapper mapper = new ModelMapper();
mapper.typeMap(CustomerDTO.class, Customer.class).addMappings(m -> {
m.map(CustomerDTO::getName, Customer::setFullName);
});
Now, mapping will still work properly.
Mapping Nested Objects
Imagine:
Customer Entity → Contains Address Entity
public class Address {
private String street;
private String city;
private String zip;
}
@Entity
public class Customer {
...
@OneToOne
private Address address;
}
CustomerDTO → Flattens the fields
public class CustomerDTO {
private String fullName;
private String city;
private String street;
}
Custom Mapping
modelMapper.createTypeMap(Customer.class, CustomerDTO.class).addMappings(mapper -> {
mapper.map(src -> src.getAddress().getStreet(), CustomerDTO::setStreet);
mapper.map(src -> src.getAddress().getCity(), CustomerDTO::setCity);
});
ModelMapper handles nested object transformations smoothly.
Conclusion
ModelMapper is a powerful and simple tool that:
- Removes repetitive mapping code
- Makes controllers and services cleaner
- Handles advanced/custom mappings
- Works perfectly with REST APIs and DTO patterns
If you’re building a Spring Boot project with entities + DTOs (which almost every real-world app does),
ModelMapper can save you tons of time and reduce errors.