SpringBoot中如何将含集合参数的对象映射为单个对象集合(无外部库实现)
Problem Description
I have the following JSON response:
{ "1": "string", "2": "string", "3": "string", "4": "string", "collection": [ { "col_1_1": "string", "col_1_2": 37, "col_1_3": "string", "col_1_4": "string" }, { "col_2_1": "string", "col_2_2": 37, "col_2_3": "string", "col_2_4": "string" } ] }
I want to convert it to this flattened structure:
[ { "1": "string", "2": "string", "3": "string", "4": "string", "col_1_1": "string", "col_1_2": 37, "col_1_3": "string", "col_1_4": "string" }, { "1": "string", "2": "string", "3": "string", "4": "string", "col_2_1": "string", "col_2_2": 37, "col_2_3": "string", "col_2_4": "string" } ]
My corresponding Java POJOs are:
public class MainDTO { private String param1; // Maps to JSON "1" private String param2; // Maps to JSON "2" private String param3; // Maps to JSON "3" private String param4; // Maps to JSON "4" private Set<CollectionDTO> collection; // Getters and Setters } class CollectionDTO { private String param1; // Maps to JSON col_x_1 private Integer param2; // Maps to JSON col_x_2 (note: original JSON has numeric value 37) private String param3; // Maps to JSON col_x_3 private String param4; // Maps to JSON col_x_4 // Getters and Setters }
I've tried several approaches without success. I want my mapper method to only accept a MainDTO parameter (ideally in the form MainDTO maptoDto(MainDTO dto)). I previously wrote methods that take both MainDTO and CollectionDTO, but I know I need to handle the mapping internally to extract properties from each collection element.
Can I achieve this without external libraries? How exactly? Have others faced similar issues?
Solution: Flattening Without External Libraries
Absolutely! You don't need any external libraries for this. The core logic is straightforward: iterate over each element in the collection and copy the top-level fields from MainDTO into a new merged object for each element. Here's a step-by-step implementation:
1. Define a Merged DTO Class
First, create a MergedDTO to hold the combined fields from both MainDTO and CollectionDTO. Match the field names to your target JSON structure:
public class MergedDTO { // Fields from MainDTO private String param1; private String param2; private String param3; private String param4; // Fields from CollectionDTO private String colParam1; private Integer colParam2; private String colParam3; private String colParam4; // Full-parameter constructor public MergedDTO(String param1, String param2, String param3, String param4, String colParam1, Integer colParam2, String colParam3, String colParam4) { this.param1 = param1; this.param2 = param2; this.param3 = param3; this.param4 = param4; this.colParam1 = colParam1; this.colParam2 = colParam2; this.colParam3 = colParam3; this.colParam4 = colParam4; } // Getters and Setters (required if you need to serialize/deserialize) }
2. Implement the Mapper Method
If your goal is to generate the list structure from your target JSON, return a List<MergedDTO>. If you strictly need to adhere to the MainDTO maptoDto(MainDTO dto) signature, you can modify MainDTO to include a field for the flattened list (see the commented code below):
import java.util.ArrayList; import java.util.List; import java.util.Set; public class DtoMapper { // Preferred method: Returns the flattened list directly public List<MergedDTO> mapToFlattenedList(MainDTO dto) { List<MergedDTO> result = new ArrayList<>(); // Handle null cases to avoid NullPointerException if (dto == null || dto.getCollection() == null || dto.getCollection().isEmpty()) { return result; } // Extract top-level fields from MainDTO once String mainParam1 = dto.getParam1(); String mainParam2 = dto.getParam2(); String mainParam3 = dto.getParam3(); String mainParam4 = dto.getParam4(); // Merge top-level fields with each CollectionDTO element for (CollectionDTO colDto : dto.getCollection()) { MergedDTO merged = new MergedDTO( mainParam1, mainParam2, mainParam3, mainParam4, colDto.getParam1(), colDto.getParam2(), colDto.getParam3(), colDto.getParam4() ); result.add(merged); } return result; } // Optional: If you must return MainDTO (modify MainDTO to add a flattenedCollection field) // public MainDTO maptoDto(MainDTO dto) { // List<MergedDTO> flattenedList = mapToFlattenedList(dto); // dto.setFlattenedCollection(flattenedList); // Add this field to MainDTO // dto.setCollection(null); // Optional: Clear the original collection if needed // return dto; // } }
3. Key Notes
- Null Safety: Always validate
MainDTOandcollectionfor null/empty values to prevent runtime errors. - Efficient Field Extraction: Extract the top-level
MainDTOfields once outside the loop instead of inside, to avoid redundant calls. - Common Use Case: This kind of flattening (passing parent object properties to child elements) is extremely common—developers encounter it in report generation, API response formatting, and data export scenarios all the time.
Test Example
Here's how you'd use the mapper with sample data:
// Create sample MainDTO MainDTO mainDto = new MainDTO(); mainDto.setParam1("string"); mainDto.setParam2("string"); mainDto.setParam3("string"); mainDto.setParam4("string"); // Create sample CollectionDTO elements CollectionDTO col1 = new CollectionDTO(); col1.setParam1("string"); col1.setParam2(37); col1.setParam3("string"); col1.setParam4("string"); CollectionDTO col2 = new CollectionDTO(); col2.setParam1("string"); col2.setParam2(37); col2.setParam3("string"); col2.setParam4("string"); mainDto.setCollection(Set.of(col1, col2)); // Run the mapper DtoMapper mapper = new DtoMapper(); List<MergedDTO> flattenedResult = mapper.mapToFlattenedList(mainDto);
Serializing flattenedResult will produce exactly the JSON structure you're targeting.
内容的提问来源于stack exchange,提问作者mat373

