Understanding DTOs in Java Spring Boot cover image

13/01/2025

Understanding DTOs in Java Spring Boot

In Java Spring Boot development, **DTO** (Data Transfer Object) is a common design pattern used to transfer data between different layers of an application. This pattern is especially useful in complex systems where entit

#spring-boot #java

In Java Spring Boot development, DTO (Data Transfer Object) is a common design pattern used to transfer data between different layers of an application. This pattern is especially useful in complex systems where entities and business logic need to be decoupled from the data being sent and received over APIs.

What is a DTO?

A DTO is a simple, flat object containing only fields and getters/setters. Its primary purpose is to carry data from one part of an application to another. Unlike entities, DTOs do not contain any business logic or persistence-related annotations (e.g., @Entity, @Table). They are typically used in the Service Layer or Controller Layer to structure data exchanged with external systems or the front end.

Why use DTOs?

  1. Encapsulation of data: DTOs hide irrelevant or sensitive fields from being exposed, ensuring that only required data is shared.
  2. Data transformation: DTOs allow easy transformation of entity objects into a more convenient format for APIs or clients.
  3. Decoupling layers: They help decouple the persistence layer (entities) from the presentation layer (API responses).
  4. Performance optimization: By selecting only the necessary fields, DTOs reduce the amount of data transmitted over the network.

How to use DTOs in Spring Boot

Define a DTO class

Create a class that represents the data structure needed for a specific use case.

public class UserDTO {
    private Long id;
    private String name;
    private String email;

    // Constructors, Getters, and Setters
    public UserDTO(Long id, String name, String email) {
        this.id = id;
        this.name = name;
        this.email = email;
    }

    // Getters and setters..
}

Guide to Lombok in Spring Boot with Maven

Convert entity to DTO

Use a mapper or manual conversion logic in your service layer.

@Service
public class UserService {
    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    public UserDTO getUserById(Long id) {
        User user = userRepository.findById(id)
            .orElseThrow(() -> new RuntimeException("User not found"));

        return new UserDTO(user.getId(), user.getName(), user.getEmail());
    }
}

Return DTOs in Controllers

Use the DTO in the controller to respond to API requests.

@RestController
@RequestMapping("/users")
public class UserController {
    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @GetMapping("/{id}")
    public ResponseEntity<UserDTO> getUser(@PathVariable Long id) {
        UserDTO userDTO = userService.getUserById(id);
        return ResponseEntity.ok(userDTO);
    }
}

Using libraries for mapping

Manual mapping can be repetitive and error-prone. Libraries like MapStruct or ModelMapper can simplify this process:

MapStruct: A compile-time mapper that generates boilerplate mapping code.

MapStruct – Java bean mappings, the easy way!

ModelMapper: A runtime mapper with powerful configuration options.

ModelMapper - Simple, Intelligent, Object Mapping.

Best practices for DTOs

  1. Separate read and write DTOs: Use different DTOs for input (e.g., CreateUserDTO) and output (e.g., UserDTO) to enforce clear separation of concerns.
  2. Validation: Use annotations like @NotNull, @Size, or @Pattern in input DTOs to validate incoming data.
  3. Keep DTOs lightweight: Avoid including unnecessary fields or methods.
  4. Documentation: Clearly document the purpose and structure of each DTO.

DTOs are an essential part of Java Spring Boot applications, promoting clean architecture, improved performance, and better maintainability. By leveraging DTOs effectively, developers can build scalable and secure applications that are easy to maintain and evolve over time. Whether using manual mapping or libraries like MapStruct, incorporating DTOs into your design ensures robust and decoupled code.