Reputation: 1680
I want to return JSON from Rest API endpoint as keys with values. Example:
{
"terminal 1":
{"date":"2018-10-06T00:00:00.000+0000","volume":111,"count":1},
"terminal 2":
{"date":"2018-11-06T00:00:00.000+0000","volume":122,"count":1}
}
How I can add the keys? It should be I suppose like this:
List<String<List<TopTerminalsDTO>>>>
Can you give me some code example?
Latest attempt to clean the final code:
@GetMapping("/terminals")
public ResponseEntity<Map<Integer, List<TopTerminalsDTO>>> getTopTerminalsVolumes(
@RequestParam(value = "start_date", required = true) String start_date,
@RequestParam(value = "end_date", required = true) String end_date) {
LocalDateTime start_datel = LocalDateTime.now(Clock.systemUTC());
LocalDateTime end_datel = LocalDateTime.now(Clock.systemUTC());
final List<PaymentTransactionsDailyFacts> list = dashboardRepository.top_daily_transactions(start_datel, end_datel);
final Collector<PaymentTransactionsDailyFacts, List<TopTerminalsDTO>, List<TopTerminalsDTO>> terminalsCollector =
Collector.of(
ArrayList::new,
(terminals, p) -> terminals.add(mapper.toTopTerminalsDTO(p)),
(accumulator, terminals) -> {
accumulator.addAll(terminals);
return accumulator;
}
);
final Map<Integer, List<TopTerminalsDTO>> final_map =
list.stream()
.filter(p -> p.getTerminal_id() != null)
.collect(Collectors.groupingBy(p -> p.getTerminal_id(), terminalsCollector));
return ResponseEntity.ok(final_map);
}
Upvotes: 1
Views: 1616
Reputation: 21144
This is what a Javascript dictionary
looks like.
In Java, the correct representation is a Map<String, TopTerminalDto>
.
Say you have an ordered List, and you want to return a Map
with generated keys terminal{index}
.
final List<TopTerminalDto> list = ...
final Map<String, TopTerminalDto> map =
IntStream.range(0, list.size())
.boxed()
.collect(toMap(i -> "terminal" + i, i -> list.get(i)));
The Spring endpoint would become:
@GetMapping("terminals")
Map<String, TopTerminalDto> getTopTerminalVolumes() { ... }
The ResponseEntity
is not mandatory in Spring.
Remember to work as much as possible via Stream
(s), to produce results without intermediate temporary state.
Additional example:
final List<PaymentTransactionsDailyFacts> list =
dashboardRepository.top_daily_transactions(start_datel, end_datel);
final Map<String, TopTerminalDto> map =
list.stream()
.collect(toMap(p -> p.getTerminal(), this::toDto))
// Conversion method
private TopTerminalDto toDto(final PaymentTransactionsDailyFacts p) {
// Implement conversion to Dto
}
For multiple values associated with a terminal:
final Map<Integer, List<TopTerminalDto>> map =
list.stream()
.filter(p -> p.getTerminal() != null)
.collect(groupingBy(
p -> p.getTerminal(),
Collector.of(
ArrayList::new,
(terminals, p) -> terminals.add(toDto(p)),
(accumulator, terminals) -> {
accumulator.addAll(terminals);
return accumulator;
}
)
));
You can clean the code by extracting the Collector.
final Collector<Integer, List<TopTerminalDto>, List<TopTerminalDto>> terminalsCollector =
Collector.of(
ArrayList::new,
(terminals, p) -> terminals.add(toDto(p)),
(accumulator, terminals) -> {
accumulator.addAll(terminals);
return accumulator;
}
)
final Map<Integer, List<TopTerminalDto>> map =
list.stream()
.filter(p -> p.getTerminal() != null)
.collect(groupingBy(p -> p.getTerminal(), terminalsCollector));
Upvotes: 1
Reputation: 2516
Following your JSON, testDate()
should return Map<String, TopTerminalsDTO>
instead of List
.
Map<String, TopTerminalsDTO> result = newHashMap();
for (int i = 0; i <= 10; i++) {
TopTerminalsDTO ttDto = new TopTerminalsDTO();
ttDto.setCount(ThreadLocalRandom.current().nextInt(20, 500 + 1));
LocalDate localDate = LocalDate.now().minus(Period.ofDays((new Random().nextInt(365 * 70))));
Date date = Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
ttDto.setDate(date);
ttDto.setVolume(ThreadLocalRandom.current().nextInt(300, 5000 + 1));
result.put("terminal "+i, ttDto)
}
return result;
And, of course, change response type of rest method to ResponseEntity<Map<String, TopTerminalsDTO>>
Upvotes: 2