I am trying to generate a report with cascade values a shown below:
| Country | City | Town |
--------------------------------------
| Country A | City X | Town 1 |
| Country A | City X | Town 2 |
| Country A | City Y | Town 1 |
| Country A | City Y | Town 2 |
| Country B | City Q | Town 1 |
| Country B | City Q | Town 2 |
| Country B | City T | Town 1 |
| Country B | City T | Town 2 |
I can properly generate Country and City as shown above, but I pass a j
index value for each city as shown below. However, for towns, I will also need another index variable like k
and loop.
public MultipartFile exportData() throws IOException {
// code omitted for brevity
int rowCount = 0;
final List<CountryDTO> countryList = countryService.findAll();
int iSize = countryList.size();
for (int i = 0; i < iSize; i++) {
int jSize = countryList.get(i).getCityList().size();
for (int j = 0; j < jSize; j++) {
int kSize = countryList.get(i).getCityList().get(j).getTownList().size();
for (int j = 0; k < kSize; k++) {
Row row = sheet.createRow(rowCount++);
write(countryList.get(i), row, j, k);
}
}
}
// code omitted for brevity
}
private static void write(CountryDTO country, Row row, int j) {
Cell cell = row.createCell(0);
cell.setCellValue(country.getName());
cell = row.createCell(1);
cell.setCellValue(country.getCityList().get(j).getName());
cell = row.createCell(2);
cell.setCellValue(country.getCityList().get(j).getTownList().get(k).getName());
}
I am not sure if there is a better approach for this. As I am new for generating report in Java, I have no idea how to proceed with the following approach (if it is ok I will use this approach as it was already used in the current project).
You could use for-each syntax rather than indexed for loop.
for( Country country : countryService.findAll() )
{
for( City city : country.getCityList() )
{
for( Town town : city.getTownList() )
{
write( country , city , town ) ;
}
}
}
Notice that we redefined the write
method to be ignorant of the originating data structure. It’s job is to write data, not retrieve it. No need for that method to understand the nested lists.
Study up on Separation Of Concerns. A method and a class should know as little about the outside world as possible. This prevents your code from becoming “brittle”, where one little change causes your code to break all over the place.
I would go further in Java 16+ to pass a record object to the write
method. A record is brief way to write a class whose main purpose is to communicate data transparently and immutably. The compiler implicitly creates the constructor, getters, equals
& hashCode
, and toString
.
record CountryCityTown( String country , String city , String town ) {}
Change write
method to take a single object of that type.
void write ( CountryCityTown countryCityTown ) { … }