Nested DTOs help organize related data inside other data objects. They make it easier to send or receive complex information in a clear way.
Nested DTOs in Spring Boot
Start learning this pattern below
Jump into concepts and practice - no test required
or
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Introduction
Syntax
Spring Boot
public class OuterDTO { private InnerDTO inner; // getters and setters public static class InnerDTO { private String field; // getters and setters } }
Nested DTOs are usually static inner classes or separate classes referenced inside another DTO.
Use getters and setters or Lombok annotations to access nested fields.
Examples
Spring Boot
public class UserDTO { private String name; private AddressDTO address; // getters and setters } public class AddressDTO { private String street; private String city; // getters and setters }
Spring Boot
import java.util.List; public class OrderDTO { private int id; private List<ItemDTO> items; // getters and setters } public class ItemDTO { private String productName; private int quantity; // getters and setters }
Spring Boot
public class OuterDTO { private InnerDTO inner; public static class InnerDTO { private String detail; // getters and setters } // getters and setters }
Sample Program
This example defines a PersonDTO with a nested ContactDTO inside it. The main method creates a person with contact details and prints them.
Spring Boot
package com.example.demo.dto; public class PersonDTO { private String name; private ContactDTO contact; public PersonDTO() {} public PersonDTO(String name, ContactDTO contact) { this.name = name; this.contact = contact; } public String getName() { return name; } public void setName(String name) { this.name = name; } public ContactDTO getContact() { return contact; } public void setContact(ContactDTO contact) { this.contact = contact; } public static class ContactDTO { private String email; private String phone; public ContactDTO() {} public ContactDTO(String email, String phone) { this.email = email; this.phone = phone; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getPhone() { return phone; } public void setPhone(String phone) { this.phone = phone; } } } // Usage example in a main method or test class Main { public static void main(String[] args) { PersonDTO.ContactDTO contact = new PersonDTO.ContactDTO("alice@example.com", "123-456-7890"); PersonDTO person = new PersonDTO("Alice", contact); System.out.println("Name: " + person.getName()); System.out.println("Email: " + person.getContact().getEmail()); System.out.println("Phone: " + person.getContact().getPhone()); } }
Important Notes
Nested DTOs help keep related data together and improve code organization.
Remember to provide getters and setters for nested objects to access their fields.
Using static nested classes avoids unnecessary references to the outer class instance.
Summary
Nested DTOs group related data inside other data objects.
They make it easier to handle complex data structures in Spring Boot.
Use static inner classes or separate classes to create nested DTOs.
Practice
1. What is the main purpose of using
Nested DTOs in Spring Boot applications?easy
Solution
Step 1: Understand DTO role
DTOs (Data Transfer Objects) are used to carry data between processes or layers.Step 2: Identify Nested DTO purpose
Nested DTOs group related data inside other DTOs to represent complex data structures clearly.Final Answer:
To group related data inside other data objects for better structure -> Option BQuick Check:
Nested DTOs = Group related data [OK]
Hint: Nested DTOs organize data inside other objects [OK]
Common Mistakes:
- Thinking nested DTOs improve database speed
- Confusing DTOs with entities
- Assuming nested DTOs replace controllers
2. Which of the following is the correct way to declare a nested DTO class inside a parent DTO in Spring Boot?
easy
Solution
Step 1: Check nested class modifiers
Static nested classes are recommended for DTOs to avoid implicit reference to outer class.Step 2: Validate access modifiers
Public static nested class with private fields and getters/setters is standard practice.Final Answer:
public class ParentDTO { public static class ChildDTO { private String name; } } -> Option CQuick Check:
Static nested class with public modifier = public class ParentDTO { public static class ChildDTO { private String name; } } [OK]
Hint: Use public static nested class for nested DTOs [OK]
Common Mistakes:
- Using non-static nested classes causing memory leaks
- Declaring nested class as private making it inaccessible
- Using public fields instead of private with getters/setters
3. Given the following nested DTO classes, what will be the output of
System.out.println(order.getCustomer().getName()); if order is initialized as below?public class OrderDTO {
private CustomerDTO customer;
public CustomerDTO getCustomer() { return customer; }
public void setCustomer(CustomerDTO customer) { this.customer = customer; }
public static class CustomerDTO {
private String name;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
}
OrderDTO order = new OrderDTO();
OrderDTO.CustomerDTO cust = new OrderDTO.CustomerDTO();
cust.setName("Alice");
order.setCustomer(cust);medium
Solution
Step 1: Analyze object initialization
The customer object is created and its name is set to "Alice" before being assigned to order.Step 2: Check method calls
Calling order.getCustomer().getName() returns the name "Alice" as set previously.Final Answer:
Alice -> Option AQuick Check:
Nested DTO getter returns set value = Alice [OK]
Hint: Set nested DTO fields before accessing getters [OK]
Common Mistakes:
- Forgetting to set nested DTO before calling getter
- Confusing null with empty string
- Assuming compilation error due to nested class
4. Identify the error in the following nested DTO code snippet:
public class UserDTO {
private AddressDTO address;
public static class AddressDTO {
private String city;
public String getCity() { return city; }
public void setCity(String city) { this.city = city; }
}
public AddressDTO getAddress() { return address; }
public void setAddress(AddressDTO address) { this.address = address; }
}
UserDTO user = new UserDTO();
user.getAddress().setCity("Paris");medium
Solution
Step 1: Check object initialization
The address field in UserDTO is never initialized, so it is null by default.Step 2: Analyze method call
Calling user.getAddress().setCity("Paris") tries to call setCity on null, causing NullPointerException.Final Answer:
NullPointerException because address is not initialized -> Option DQuick Check:
Uninitialized nested DTO causes NullPointerException [OK]
Hint: Always initialize nested DTO before calling its methods [OK]
Common Mistakes:
- Assuming default constructor initializes nested DTO
- Thinking compilation error occurs
- Ignoring possibility of NullPointerException
5. You have a nested DTO structure where
OrderDTO contains a list of ItemDTO objects. You want to convert this nested DTO into a flat list of item names using Java streams. Which code snippet correctly achieves this?public class OrderDTO {
private List<ItemDTO> items;
public List<ItemDTO> getItems() { return items; }
public void setItems(List<ItemDTO> items) { this.items = items; }
public static class ItemDTO {
private String name;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
}
OrderDTO order = ...; // initialized with itemshard
Solution
Step 1: Understand stream mapping
To get a list of names, map each ItemDTO to its name using map(OrderDTO.ItemDTO::getName).Step 2: Collect results
Use toList() (Java 16+) or collect(Collectors.toList()) to gather results into a list.Final Answer:
List<String> names = order.getItems().stream().map(OrderDTO.ItemDTO::getName).toList(); -> Option AQuick Check:
Stream map + toList() = List<String> names = order.getItems().stream().map(OrderDTO.ItemDTO::getName).toList(); [OK]
Hint: Use stream().map(...).toList() to extract nested DTO fields [OK]
Common Mistakes:
- Using flatMap instead of map for simple field extraction
- Calling map on List directly without stream()
- Accessing private fields without getter
