I have a REST API that fetches a list of entities that is then mapped to DTOs. The requests take quite a lot of time because for 10 fetched entities it's about 1.5seconds. The query to the DB seems OK - it takes about 100ms.
I found that this one piece of code during the mapping entitiy->DTO phase takes about 80% of the time:
Map<String, List<DailyTimeDTO>> dailyTimesGroupedByClientStream = timesheetReport.getDailyTimes()
.stream()
.filter(dailyTime -> dailyTime.getWorkTime() != null)
.map(DailyTimeDTO::create)
.collect(Collectors.groupingBy(DailyTimeDTO::getClient));
With about 30-40 DailyTime objects it takes 80-100 ms and it is ran for each entity while mapping so when mapping 10 entities the request takes about 1.5 seconds and for 100 entities it takes a whole lot more.
I tried implementing it without the stream but it didn't really help (as below). I tried debugging what takes so much time (using the System.nanoTime() as below) but each iteration of the loop takes about 5 microseconds (so 0.005 ms). But the whole loop takes about 80-100 ms. So where does so much more time get lost? Is it the overhead of iterating over a list multiple times? Is there something I can do about besides figuring out a different way to perform this mapping?
dailyTimes.forEach( dailyTime -> {
long startTime = System.nanoTime();
if (dailyTime == null || dailyTime.getWorkTime() == null) return;
DailyTimeDTO dailyTimeDTO = DailyTimeDTO.create(dailyTime);
map.add(dailyTimeDTO.getClient(), dailyTimeDTO);
log.info("Iteration full {}", (System.nanoTime() - startTime) / 1000);
});
The DailyTimeDTO::create is nothing special:
public static DailyTimeDTO create(DailyTime dailyTime) {
return DailyTimeDTO.builder()
.client(dailyTime.getClient() == null ? "" : dailyTime.getClient().getClientName())
.project(dailyTime.getProject() == null ? "" : dailyTime.getProject().getProjectName())
.hours(dailyTime.getWorkTime())
.build();
}