What Is DTO in Java? Spring Boot Entity vs DTO, MapStruct Guide (2026)

A DTO (Data Transfer Object) is a simple object used in Java and Spring Boot REST APIs to transfer data in a secure, controlled, and lightweight way.

This guide answers the most common questions: What is a DTO?, Why use DTOs?, What is the difference between Entity and DTO?, How to use MapStruct for DTO mapping?

What is DTO in Java? Spring Boot Entity vs DTO differences and MapStruct mapping guide 2026
DTOs control the API output, improve security, and reduce maintenance costs.

What Is a DTO? (Data Transfer Object)

A DTO (Data Transfer Object) is an object that carries data between an application and external systems — such as a REST API client — without containing any business logic. First described by Martin Fowler in Patterns of Enterprise Application Architecture, this design pattern has become a de facto standard in the Java world, particularly for Spring Boot projects.

Core purpose: Expose a controlled, contract-based API response without directly revealing the database model (Entity).

In short: the Entity is the language of the database; the DTO is the language of the API. Keeping them separate reduces layer coupling, improves security, and simplifies maintenance.

Entity to DTO conversion flow in Spring Boot architecture — Controller Service Repository layers
Controller → Service → Repository → Entity → Mapper → DTO → Response

Why Use DTOs? What Problem Do They Solve?

Returning the Entity class directly as an API response may seem convenient in the short term, but it causes serious problems in real-world projects. There are three core reasons to use DTOs:

1) Security

Entity classes often contain sensitive or unnecessary fields like password, createdAt, or internalStatus. If the Entity is returned directly, these fields can unintentionally appear in the API response. DTOs only carry explicitly defined fields, preventing sensitive data leaks.

2) API Stability

When the database schema changes, the Entity class changes too. If the Entity is used directly, this breaks all existing clients. A DTO establishes an independent API contract — even if the database changes, the API response can remain stable.

3) Performance

Entities contain all database fields. Sending only the required fields over the network reduces JSON payload size, lowers bandwidth consumption, and creates a noticeable performance difference especially for mobile clients.

Spring Boot API security with DTO — protecting sensitive fields from being exposed
Only the required fields are exposed to the outside world through the DTO.

Entity vs DTO: What Is the Difference?

Mixing up the responsibilities of Entity and DTO is a common mistake in Spring Boot projects. The table below summarizes the key differences:

PropertyEntityDTO
PurposeDatabase modelAPI contract
LayerPersistence (JPA)Presentation / Service
Annotations@Entity, @Table, @ColumnPlain POJO or record
SecurityExposes all fields — riskyOnly explicitly defined fields
Change impactCoupled to the databaseIndependent from the API
ValidationDB constraints@NotNull, @Email, @Size
Rule: An Entity should never be returned directly from a @RestController method.

Spring Boot DTO Example

Below is a simple customer Entity and its corresponding DTO:

Entity (database model):

@Entity
@Table(name = "customers")
public class Customer {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String firstname;
    private String lastname;
    private String email;
    private String password;         // should NOT be exposed via API
    private LocalDateTime createdAt; // should NOT be exposed via API
}

DTO (API contract — only required fields):

public class CustomerDto {
    private Long id;
    private String firstname;
    private String lastname;
    private String email;
    // password and createdAt are NOT here
}

With this structure, password and createdAt will never appear in the API response.


Entity → DTO Mapping with MapStruct

Writing Entity-to-DTO conversions manually is tedious and error-prone. MapStruct automatically generates this conversion code at compile time. Because it doesn't use reflection, it is significantly faster than alternatives like ModelMapper.

pom.xml dependency:

<dependency>
    <groupId>org.mapstruct</groupId>
    <artifactId>mapstruct</artifactId>
    <version>1.5.5.Final</version>
</dependency>

Mapper interface:

@Mapper(componentModel = "spring")
public interface CustomerMapper {
    CustomerDto toDto(Customer customer);
    Customer toEntity(CustomerDto dto);
    List<CustomerDto> toDtoList(List<Customer> customers);
}

Usage in the service layer:

@Service
@RequiredArgsConstructor
public class CustomerService {
    private final CustomerRepository repository;
    private final CustomerMapper mapper;

    public CustomerDto getById(Long id) {
        Customer customer = repository.findById(id)
            .orElseThrow(() -> new RuntimeException("Customer not found"));
        return mapper.toDto(customer);
    }
}

MapStruct generates the toDto() implementation at compile time. There is zero runtime overhead since no reflection is involved.


Request DTO vs Response DTO

In real-world projects, it is best practice to define separate DTO classes for incoming requests and outgoing responses. This allows validation rules and returned fields to be managed independently:

Request DTO — validates incoming data:

public class CreateCustomerRequest {
    @NotBlank(message = "First name is required")
    private String firstname;

    @NotBlank(message = "Last name is required")
    private String lastname;

    @Email(message = "Please enter a valid email")
    @NotBlank
    private String email;

    @Size(min = 8, message = "Password must be at least 8 characters")
    private String password;
}

Response DTO — fields exposed to the outside world:

public class CustomerResponse {
    private Long id;
    private String firstname;
    private String lastname;
    private String email;
    // password is NOT here
}

Usage in the controller layer:

@PostMapping("/customers")
public ResponseEntity<CustomerResponse> create(
        @RequestBody @Valid CreateCustomerRequest request) {
    CustomerResponse response = customerService.create(request);
    return ResponseEntity.status(HttpStatus.CREATED).body(response);
}

DTO with Java Record (Java 17+)

Introduced in Java 16, the record construct is the most modern and concise way to create immutable DTOs. It auto-generates getters, equals, hashCode, and toString:

public record CustomerDto(
    Long id,
    String firstname,
    String lastname,
    String email
) {}

Records are immutable by design, making them thread-safe and eliminating the risk of accidental data mutation. They are fully compatible with Spring Boot 3.x.

Note: Records are final by default and do not support inheritance. If you need to extend existing DTO classes, use the classic POJO approach instead.


DTO Best Practices (2026)

  • Never return an Entity directly. Every @RestController method should return a DTO.
  • Separate Request and Response DTOs. Using the same class for both input and output becomes unmanageable over time.
  • Put validation annotations in the Request DTO. Add @NotNull, @Email, @Size directly to the DTO.
  • Prefer MapStruct, avoid ModelMapper. Compile-time mapping is faster and type-safe.
  • Manage API versioning through DTOs. Separate DTOs like CustomerDtoV1 and CustomerDtoV2 preserve backward compatibility.
  • Consider Java record if you're on Java 17+. Especially ideal for read-only response DTOs.

Frequently Asked Questions

Is using a DTO mandatory in Spring Boot?

Not technically. In small personal projects, the Entity can be used directly. However, in every real-world production project, using DTOs is strongly recommended. Security vulnerabilities, API breakage, and maintenance problems typically emerge in projects that skip DTOs.

What is the difference between a DTO and a POJO?

A POJO (Plain Old Java Object) is any simple Java class that is not tied to a specific framework or interface. A DTO is a design pattern whose purpose is to carry data. Every DTO is a POJO, but not every POJO is a DTO.

Should I use Projection or DTO?

JPA Projections fetch only specific columns at the query level, which is great for database performance. DTOs represent the API contract and service-layer data transfer. The two can be combined: use a JPA Projection to pull minimal data from the database, then convert it to a Response DTO.

Can a DTO contain business logic?

No. A DTO should only carry data. Calculations, validations, and transformation logic belong in the service layer. Adding business logic to a DTO mixes responsibilities and reduces testability.

How do I use Lombok with DTOs?

Lombok's @Data, @Getter, @Setter, and @Builder annotations are commonly used with DTO classes. @Builder is especially useful for easily constructing DTO instances in test code.


Conclusion

Using DTOs makes Spring Boot APIs more secure, maintainable, and scalable. Exposing the Entity directly may seem faster in the short term, but it leads to security vulnerabilities, API breakage, and maintenance headaches down the road.

Automate conversions with MapStruct, separate Request and Response DTOs, and evaluate Java records for immutable responses. These three steps alone significantly improve the long-term quality of your project.

Related posts:

Latest Software Developers - Yazılım Blog Yazarı Profil Resmi

Author

LatestSoftwareDevelopers

Blog where the most up-to-date software is followed.

Comments on Java

Leave a Reply

Your email address will not be published. Required fields are marked * *