The DTO pattern is an abbreviation for Data Transfer objects. Unlike entity objects, the data transfer objects do not have entities.
The DTOs exchange data between the client and the entities in the database. You can think of them as a partial view of an entity.
DTOs work with both GET and POST requests depending on the use case at hand. For GET requests, you can use them to only display the relevant data to the client.
For example, you don’t want a client to view sensitive data such as passwords, card details, or an address. In this tutorial, you will learn how to use the DTO pattern in Spring Boot.
Prerequisites
- Knowledge of Java programming language.
- Java development kit(JDK8) and above.
- IntelliJ IDEA community edition – development environment for the Java programming language.
Project setup
To create a new project, go to spring initializr, and select Maven on the Project section. Since you are using Java, select Java in the Language section.
In the Spring Boot section, select version 3.x.x where x is the latest version. In the Project metadata section, fill the respective sections as shown below.
- Group – com.javawhizz
- Artifact – DTOPattern
- Package name – com.javawhizz.DTOPattern
- Packaging – Jar
- Java – 17
To add the project dependencies, press the ADD DEPENDENCIES button. On the page that opens, search and select Spring Web and Lombok.
Your project structure and dependencies should be as shown below.

- Spring Web – a library of the spring framework runtime for creating web applications.
- Lombok – a library that helps reduce boilerplate code by generating helper methods.
Press the GENERATE button to generate a ZIP file of your Spring Boot project. Unzip the project and import it into IntelliJ.
Create a user model
Under the package src/main/java/com/javawhizz/DTOPattern, create a package named user. Create a file named User.java in the user package and copy and paste the following code into the file.
package com.javawhizz.DTOPattern.user; import lombok.AllArgsConstructor; import lombok.Data; @Data @AllArgsConstructor public class User { private Long userId; private String firstName; private String lastName; private String email; private String password; }
You should add the @Data
annotation to the class to generate getter and setter methods. The @AllArgsContructor
helps you to create an instance that contains all the properties.
The User.java file defines a user with the properties id, first name, last name, email, and password.
When creating a user, you should pass an instance of this class but when fetching a user you should create a DTO. The reason for this is that the response should not have the password.
Create a user repository
Create a file named UserRepository.java in the user package. Copy and paste the following code into the file.
package com.javawhizz.DTOPattern.user; import org.springframework.stereotype.Component; import java.util.List; @Component public class UserRepository { public List<User> findAllUsers(){ return List.of( new User(1L,"john","doe", "john@javawhizz.com","password123"), new User(2L,"mary","public", "mary@javawhizz.com","password1234"), new User(3L,"isaac","newton", "isaac@javawhizz.com","password4321"), new User(4L,"elon","musk", "elon@javawhizz.com","password356") ); } }
The @Component
annotation creates a bean of the class and adds it to the spring context. This happens during component scanning and you can inject the class into any class.
Since the motive of this tutorial is to show you how to use the DTO pattern, there is no need to have persistent data.
The findAllUsers()
method returns the list of users defined using the List.of()
method. Note that the data returned by the list contains the password for the user.
Create a user DTO
Create a file named UserDTO.java in the user package and copy and paste the following code into the file.
package com.javawhizz.DTOPattern.user; public record UserDTO( Long userId, String firstName, String lastName, String email ) { }
Since the DTO does not have any business logic, the best approach to use when creating it is by using a record.
In the UserDTO.java file, you have defined a record with the fields user ID, first name, last name, and email. Note that the record does not have the password field.
You will use the record to map the user data fetched from the repository to their respective DTOs.
Create a user DTO mapper
Create a file named UserDTOMapper.java in the user package and copy and paste the following code into the file.
package com.javawhizz.DTOPattern.user; import org.springframework.stereotype.Component; import java.util.function.Function; @Component public class UserDTOMapper implements Function<User, UserDTO> { @Override public UserDTO apply(User user) { return new UserDTO( user.getUserId(), user.getFirstName(), user.getLastName(), user.getEmail() ); } }
To create a user DTO mapper, we have created a class that implements the Function interface in Java. The interface represents a function that expects one argument and returns a value.
Since the interface is generic, the first parameter is for the method argument. The second parameter is for the return value. Override the apply()
method which implements the logic to map the users to DTOs.
Create a user service
Create a file named UserService.java in the user package. Copy and paste the following code into the file.
package com.javawhizz.DTOPattern.user; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import java.util.List; import java.util.stream.Collectors; @Service @RequiredArgsConstructor public class UserService{ private final UserRepository userRepository; private final UserDTOMapper userDTOMapper; public List<UserDTO> findAllUsers() { return userRepository.findAllUsers() .stream() .map(userDTOMapper) .collect(Collectors.toList()); } }
Add the @RequiredArgsConstructor
to the class. This injects the UserRepository
and UserDTOMapper
.
To return a list of user DTOs. Call the findAllUsers()
method of the user repository which returns a list of users.
Call the stream()
method from the list returned followed by the map()
method to map the list to DTOs. Pass the injected UserDTOMapper
to the map method and the mapping logic is complete.
Since the findAllUsers()
method returns a list of UserDTO
. You should call the collect()
method on the map and pass the argument Collectors.toList()
.
Create a user controller
Create a file named UserController.java in the user package. Copy and paste the following code into the file.
package com.javawhizz.DTOPattern.user; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.List; @RestController @RequestMapping("api/v1/users") @RequiredArgsConstructor public class UserController { private final UserService userService; @GetMapping public List<UserDTO> findAllUsers(){ return userService.findAllUsers(); } }
The @RestController
annotation shows that the controller works with REST data. Add the @RequestMapping
annotation to the class to add the base URI for the REST endpoints.
In this case, the base URI is api/v1/users and every GET method to the endpoint invokes the findAllUsers()
method. As a result, the method invokes the findAllUsers()
method of UserService
.
The UserService
method returns a list of user DTOs which in turn gets returned as the response.
Run and test the application
Open a new terminal window in IntelliJ by pressing View > Tool Windows > Terminal. Copy and paste the following command into the terminal. Press the enter button on your keyboard to run the application.
C:\Users\redhat\Documents\Projects\DTOPattern> ./mvnw spring-boot:run
If your application starts without any errors, go to localhost:8080/api/v1/users. As a result, you should have the following response displayed on the page. Note that the response does not have the password field.

Conclusion
In this tutorial, you have learned how to use the DTO pattern to protect sensitive data. In this case, you can use the DTO pattern to ensure that the client can only view the relevant data to them.
Even though you have implemented the DTO by yourself, there are libraries that you can use to realize it. One of the most common libraries to create DTOs is MapStruct.
Play around with the code for this topic to understand how the DTO pattern works. it’s also good to have an understanding of how the MapStruct library works.
Happy Hacking!
0 Comments