Peter Penzov
Peter Penzov

Reputation: 1680

Return keys with values from Rest API

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

Answers (2)

LppEdd
LppEdd

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

Bor Laze
Bor Laze

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

Related Questions