Effortlessly Create DTOs with Java Records and MapStruct in Spring Boot!

Learner, Love to make things simple, Full Stack Developer, StackOverflower, Passionate about using machine learning, deep learning and AI
Search for a command to run...

Learner, Love to make things simple, Full Stack Developer, StackOverflower, Passionate about using machine learning, deep learning and AI
No comments yet. Be the first to comment.
Spring Boot tutorials, java and spring cloud tutorials where we can cover other parts like microservices, etc.
Working with databases is a fundamental part of developing most applications, but sometimes, static SQL queries don’t meet the dynamic requirements of real-world applications. For example, what if you need to build a search feature that filters resul...
Move beyond traditional RESTful thinking. Learn how to design APIs specifically for MCP (Model Context Protocol) servers. This guide covers the shift in mindset, a practical OpenAPI 3.1 example, and a Spring Boot implementation to make your services ...

Extending Kestra to Every Corner of Your Data Stack. Introduction: The Power of Plugins Imagine you're a master chef. You don't just have one knife - you have specialized tools for every task: a paring knife for delicate work, a chef's knife for chop...
Mastering Complex Orchestration Scenarios. Introduction: The Orchestrator's Toolkit Imagine you're conducting a symphony. You don't just wave your baton - you cue sections, adjust tempo, handle surprises, and ensure harmony. That's what advanced work...
From Data Extraction to Loading - A Practical Guide Introduction: Why ETL Still Matters in the Modern Data Stack Remember when data engineering was "extract, transform, load"? Some say ETL is dead, replaced by ELT, reverse ETL, and data mesh. But her...
Building Blocks of Declarative Orchestration. Introduction: The Power of Simplicity Imagine trying to build a house without understanding bricks, beams, and blueprints. That's what using an orchestration tool without understanding its core concepts f...
In modern Spring Boot applications, Data Transfer Objects (DTOs) play a vital role in ensuring clean code, maintaining separation of concerns, and improving application security. With the advent of Java Records, creating immutable DTOs has become simpler than ever. When paired with MapStruct, an efficient mapping framework, handling object conversions becomes a breeze.
In this article, you’ll learn:
What Java Records are and why they’re great for DTOs.
How to use MapStruct to map entities to DTOs and vice versa.
A complete example showcasing DTOs with Records and MapStruct in Spring Boot.
Java Records, introduced in Java 14 (as a preview) and officially in Java 16, are a concise way to declare classes that are primarily used to store data. They are:
Immutable: Fields of records cannot be changed after the object is created.
Boilerplate-Free: Automatically generates constructors, getters, equals(), hashCode(), and toString() methods.
Example of a Record:
public record CustomerDTO(Long id, String name, String email) {}
Why use Records for DTOs?
Immutability ensures data integrity.
Compact Syntax reduces clutter, focusing on the data.
MapStruct is a Java-based code generator that simplifies mapping between objects. Instead of manually writing boilerplate mapping logic, MapStruct generates efficient and type-safe mappers at compile time.
Add the required dependencies to your pom.xml:
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>1.5.3.Final</version>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>1.5.3.Final</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
Here’s the Customer entity:
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Entity
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
// Getters and Setters
}
Define a CustomerDTO:
public record CustomerDTO(Long id, String name, String email) {}
Define an interface for mapping:
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
@Mapper(componentModel = "spring")
public interface CustomerMapper {
CustomerDTO toDTO(Customer customer);
Customer toEntity(CustomerDTO customerDTO);
}
Key Points:
The @Mapper annotation marks this as a MapStruct mapper.
The componentModel = "spring" ensures the mapper is a Spring Bean.
Use the mapper in the service layer:
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class CustomerService {
private final CustomerRepository customerRepository;
private final CustomerMapper customerMapper;
public CustomerService(CustomerRepository customerRepository, CustomerMapper customerMapper) {
this.customerRepository = customerRepository;
this.customerMapper = customerMapper;
}
public List<CustomerDTO> getAllCustomers() {
return customerRepository.findAll().stream()
.map(customerMapper::toDTO)
.collect(Collectors.toList());
}
public CustomerDTO saveCustomer(CustomerDTO customerDTO) {
Customer customer = customerMapper.toEntity(customerDTO);
Customer savedCustomer = customerRepository.save(customer);
return customerMapper.toDTO(savedCustomer);
}
}
Create a controller to expose the API:
import org.springframework.web.bind.annotation.*;
import java.util.List;
@RestController
@RequestMapping("/customers")
public class CustomerController {
private final CustomerService customerService;
public CustomerController(CustomerService customerService) {
this.customerService = customerService;
}
@GetMapping
public List<CustomerDTO> getAllCustomers() {
return customerService.getAllCustomers();
}
@PostMapping
public CustomerDTO saveCustomer(@RequestBody CustomerDTO customerDTO) {
return customerService.saveCustomer(customerDTO);
}
}
Start the Spring Boot application.
Use Postman or curl to test the endpoints:
Get all customers:
GET /customers
Save a new customer:
POST /customers
{
"name": "Alice Johnson",
"email": "alice@example.com"
}
Immutability: Records ensure DTOs are immutable, enhancing security and predictability.
Reduced Boilerplate: Records automatically generate essential methods, while MapStruct eliminates manual mapping logic.
Type-Safe Mappings: MapStruct enforces type safety during compile time, reducing runtime errors.
Combining Java Records and MapStruct is a game-changer for building clean, efficient, and maintainable Spring Boot applications. With immutable DTOs and automated object mapping, you can simplify your codebase and focus more on solving business problems.
Start integrating these tools in your projects today, and experience the difference they bring to your development workflow!
More such articles:
https://www.youtube.com/@maheshwarligade