DTOs & Mapping
A DTO (Data Transfer Object) shapes exactly what crosses your API boundary. Keeping entities private — and mapping to DTOs — protects internal fields, decouples your schema, and dodges lazy-loading traps.
Learn DTOs & Mapping in our free Java course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick reference.
Part of the free Java course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
Before You Start
You should know JPA entities and Java records , which make ideal DTOs. The validation lesson explains where request constraints belong.
What You'll Learn
The Big Idea — A Receipt, Not the Whole Ledger
💡 Analogy: Your entity is the company's full internal ledger — costs, margins, account notes, everything. You would never hand a customer the ledger; you give them a receipt (the DTO) that shows only what they should see. The receipt is shaped for the customer's needs, hides sensitive numbers, and stays the same even if you reorganize the ledger behind the scenes. Mapping is the act of writing the receipt from the ledger.
The DTO is your public contract; the entity is your private storage.
1️⃣ DTOs vs Entities
Define a response DTO with only the fields clients should see, and a request DTO with only what they may send. Records make these one-liners. The entity keeps internal fields like passwordHash that must never leak.
2️⃣ Mapping Between Them
Mapping converts entity to DTO (dropping internal fields) and DTO to entity (filling server-side fields). Do it by hand for a few types, or generate it with MapStruct as mappings multiply.
3️⃣ Why It Matters — Hiding Internal Fields
Here is a fully runnable example: an "entity" carries a passwordHash , but mapping to a DTO ensures it never appears in the output.
🧠 Quick Recall
Answer: leaking internal fields and coupling the API to the schema (plus accidental lazy-loading).
Answer: the server generates the id; the client doesn't supply it on creation.
Answer: generates type-safe mapping code at compile time from an annotated interface, no reflection or boilerplate.
🎯 YOUR TURN — Product DTOs
Design a ProductResponse and CreateProductRequest , and a mapper that hides the internal costCents .
🧩 MINI-CHALLENGE — Computed summary DTO
Map Order entities to OrderSummary DTOs that compute itemCount and totalCents .
Common Errors
- ❌ Returning entities from controllers. Leaks fields, couples schema. Fix: map to a DTO.
- ❌ Serializing lazy associations. Extra queries or LazyInitializationException . Fix: map only the needed fields into a DTO.
- ❌ One DTO for request and response. Forces awkward nullables. Fix: use separate request/response DTOs.
- ❌ Validation on entities. Mixes concerns. Fix: put constraints on request DTOs.
- ❌ Returning password/secret fields. Serious leak. Fix: never include them in response DTOs.
- ❌ Hand-mapping dozens of types. Boilerplate sprawl. Fix: adopt MapStruct.
Pro Tips
- 💡 Use records for DTOs — immutable, concise, and self-describing.
- 💡 Keep DTOs in their own package so the API contract is easy to find.
- 💡 Map at the service or controller edge , not deep in your domain.
- 💡 Let DTOs carry computed/aggregated shapes the entity doesn't store directly.
📋 Quick Reference
Concept
Idea
Note
entity
@Entity, persisted
Private storage
DTO
data transfer object
Public contract
response DTO
safe outbound fields
No secrets
request DTO
allowed inbound fields
Often no id
record DTO
record Foo(...)
Immutable carrier
mapping
entity <-> DTO
Both directions
manual mapper
static toResponse(...)
Explicit, no deps
MapStruct
@Mapper interface
Generated code
validation
on request DTO
At the boundary
📚 Resources / Keep Learning
- 📘 Records — Java 21 language guide (docs.oracle.com)
- 📗 MapStruct reference guide (mapstruct.org)
- 📗 Spring Data JPA — projections & DTOs (docs.spring.io)
❓ Frequently Asked Questions
🎉 Lesson Complete!
You now know why entities stay private, how DTOs shape your API contract, why records make ideal DTOs, how to map between entities and DTOs by hand, and when a tool like MapStruct earns its keep.
Next up: Configuration & Properties — externalizing settings with application.properties , @Value , and @ConfigurationProperties .
Practice quiz
What does DTO stand for?
- Data Transfer Object
- Database Table Object
- Direct Type Operation
- Domain Transaction Object
Answer: Data Transfer Object. DTO stands for Data Transfer Object, a simple object used to carry data across boundaries.
Why is it risky to expose JPA entities directly in API responses?
- It is faster but illegal
- It can leak internal fields and couple the API to the schema
- Entities cannot be serialized
- It improves security
Answer: It can leak internal fields and couple the API to the schema. Exposing entities can leak sensitive/internal fields and tightly couples your public API to the database schema.
A DTO is best described as...
- A database table
- A Spring bean lifecycle
- A shape tailored to a specific API request or response
- A validation engine
Answer: A shape tailored to a specific API request or response. A DTO is a purpose-built shape for transferring exactly the data a given API operation needs.
What problem do DTOs help avoid with lazy-loaded entity associations?
- Compilation errors
- Accidental serialization triggering lazy loads / LazyInitializationException
- Slow startup
- Missing annotations
Answer: Accidental serialization triggering lazy loads / LazyInitializationException. Serializing an entity can touch lazy associations, causing extra queries or LazyInitializationException; a DTO controls exactly what is exposed.
Why are Java records a natural fit for DTOs?
- They allow mutation everywhere
- They auto-connect to the database
- They replace controllers
- They are concise, immutable carriers of data
Answer: They are concise, immutable carriers of data. Records concisely declare immutable data carriers with generated accessors, equals, and toString, ideal for DTOs.
What is 'mapping' in this context?
- Drawing a UML diagram
- Converting between entities and DTOs
- Indexing a database
- Routing a URL
Answer: Converting between entities and DTOs. Mapping is converting data between entity objects and DTO objects in each direction.
What does a tool like MapStruct generate?
- Database tables
- REST endpoints
- Compile-time mapping code between types
- Validation rules
Answer: Compile-time mapping code between types. MapStruct generates type-safe mapping code at compile time, avoiding hand-written boilerplate and reflection.
Which is a good reason to keep separate request and response DTOs?
- They must always be identical
- Inbound and outbound shapes often differ (e.g. no id on create)
- Java forbids reuse
- It reduces classes
Answer: Inbound and outbound shapes often differ (e.g. no id on create). Request and response shapes commonly differ; for example a create request has no id while the response does.
Where should validation annotations typically live?
- Only on entities
- On the database
- Nowhere
- On request DTOs at the API boundary
Answer: On request DTOs at the API boundary. Putting validation on request DTOs validates input at the boundary without polluting persistence entities.
What is a downside of manual mapping compared to a mapping library?
- It is impossible
- More boilerplate to write and maintain
- It cannot compile
- It bypasses the JVM
Answer: More boilerplate to write and maintain. Manual mapping is explicit and dependency-free but means writing and maintaining repetitive conversion code.