Mastering DTO Mapping in Spring Boot 3 with ModelMapper: A Hands‑On Guide
Learn how to efficiently convert internal entities to external DTOs in Spring Boot 3 using ModelMapper, covering library comparisons, Maven setup, configuration, entity and DTO definitions, service, facade, controller implementation, and advanced features like custom mappings, property skipping, value conversion, and conditional mapping.
1. Introduction
When designing REST APIs we often need to convert internal entities to external DTOs. Several libraries can help with this conversion in Spring Boot.
Common mapping libraries
Dozer – inactive, may be deprecated.
ModelMapper – intelligent object‑mapping library with convention‑based API.
MapStruct – code generator that creates fast, type‑safe mapper implementations.
Orika – Java bean mapper useful for recursive copying.
Selma – annotation processor that generates mapping code at compile time and provides a runtime library.
2. Practical Example
2.1 Add Dependency & Configuration
<code><dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>3.2.1</version>
</dependency>
</code>Configure a ModelMapper bean in Spring:
<code>@Configuration
public class ModelMapperConfig {
@Bean
public ModelMapper modelMapper() {
return new ModelMapper();
}
}
</code>2.2 Define Entity and DTO
<code>public class Order {
private String orderNumber;
private double orderAmount;
private double tax;
private Customer customer;
private Address shippingAddress;
// getters and setters
}
public class Customer {
private String userId;
private String firstName;
private String lastName;
private String email;
// getters and setters
}
public class Address {
private String addressLine1;
private String street;
private String city;
private String postalCode;
// getters and setters
}
public class OrderDto {
public String orderNumber;
private double orderAmount;
private double tax;
private Customer customer;
private Address shippingAddress;
// getters and setters
}
</code>2.3 Facade Layer
<code>@Component
public class OrderFacade {
private final ModelMapper modelMapper;
public OrderFacade(ModelMapper modelMapper) {
this.modelMapper = modelMapper;
}
public OrderDto convert(Order order) {
return modelMapper.map(order, OrderDto.class);
}
}
</code>2.4 REST Controller
<code>@RestController
@RequestMapping("/orders")
public class OrderController {
private final OrderFacade orderFacade;
private final OrderService orderService;
public OrderController(OrderFacade orderFacade, OrderService orderService) {
this.orderFacade = orderFacade;
this.orderService = orderService;
}
@GetMapping("/{id}")
public ResponseEntity<OrderDto> getOrder(@PathVariable("id") String id) {
Order order = orderService.queryOrder();
OrderDto orderDto = orderFacade.convert(order);
return ResponseEntity.ok(orderDto);
}
}
</code>The endpoint demonstrates a full request flow that returns a mapped OrderDto.
3. Advanced ModelMapper Usage
3.1 Custom Mapping
Rename DTO fields and map them explicitly:
<code>public class OrderDto {
public String number;
// other fields
}
typeMap.addMapping(src -> src.getOrderNumber(), OrderDto::setNumber);
</code>3.2 Skipping Properties
<code>typeMap.addMappings(mapping -> mapping.skip(OrderDto::setTax));
</code>3.3 Property Value Conversion
<code>Converter<String, String> toUpperCase = ctx -> ctx.getSource() == null ? null : ctx.getSource().toUpperCase();
typeMap.addMappings(mapping -> mapping.using(toUpperCase)
.map(Order::getOrderNumber, OrderDto::setNumber));
</code>3.4 Conditional Mapping
<code>Condition<String, String> condition = ctx -> !"Pack-00001".equals(ctx.getSource());
typeMap.addMappings(mapping -> mapping.when(condition).map(Order::getOrderNumber, OrderDto2::setNumber));
</code>Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.