Как объединить список с Json java - PullRequest
2 голосов
/ 07 мая 2020

У меня есть некоторые данные БД:

//  sequence       subject       unit1       unit2        unit3
//    '2'          'math1',      'root',     'root1',     'asdf'
//    '3'          'math1',      'root',     'root1',     '2fa'
//    '4'          'math1',      'root',     'root2',     '23fasdf'
//    '5'          'math1',      'cosin',    'tan1',      ''
//    '6'          'math1',      'cosin',    'tan1',      'a'
//    '7'          'math2',      'sigma',    'alt',       '22'
//    '8'          'math2',      'sigma',    'alt',       '2fa'
//    '9'          'math2',      'sigma',    'alt',       ''
//    '10          'math2',      'ak1',      'test',      'aaaf3'
//    '11          'math2',      'ak2',      'test2',     'af3vv'

И я вызываю Spring Data JPA, используя findall() следующим образом:

List<Entity> call = findall()

Как сделать такой ответ:

[{
    math1: [{
        unit1: [{
            root: [{
                root1: ["asdf", "2fa"]
            }]
        }]
    }]
}]

Я пробовал:

 Map<String, List<Entity>> listUp_subject = collect.stream()
             .collect(Collectors.groupingBy(Entity::getSubject));

... и ...

 Map<String, Set<Entity>> collect2 = collect.stream()
            .collect(Collectors.groupingBy(Entity::getSubject, Collectors.mapping(Entity::new, Collectors.toSet())));

Но я не могу сделать это с помощью Java Stream или другим способом. Как это сделать?

1 Ответ

2 голосов
/ 11 мая 2020

1. Сбор от List<String> до Map<...> с использованием Java Stream API

Предоставленная структура вывода JSON несовместима с Map<String, List<Entity>>, но с несколькими словарями, вложенными как значения. Насколько я понимаю, есть 3 уровня: subject, unit1 и unit2. Последнее значение, не являющееся словарным, - List<String> из unit3.

Следовательно, желаемый результат - Map<String, Map<String, Map<String, List<String>>>> и цепочка Collectors.groupingBy должна быть подходящей для него:

Map<String, Map<String, Map<String, List<String>>>> map = call.stream().collect(
    Collectors.groupingBy(Entity::getSubject,                                    // Map<String, List<Entity>> by Subject
        Collectors.groupingBy(Entity::getUnit1,                                  // Map<String, Map<String, List<Entity>>> by subject, then unit1
            Collectors.groupingBy(Entity::getUnit2,                              // Map<String, Map<String, Map<String, List<Entity>>>> by subject, then unit1 and then unit2
                Collectors.mapping(Entity::getUnit3, Collectors.toList())))));   // Map<String, Map<String, Map<String, List<String>>>> by subject, then unit1, then unit2 and then values are mapped as List<String> of unit3

Обратите внимание на последнюю строку с Collectors.mapping, отображает структуру List<Entity на List<String. Все используемые мапперы доступны начиная с Java 8 (с самим API ).

2. Преобразование вывода в JSON

Прежде всего, обратите внимание, что ваш требуемый образец вывода недействителен, поскольку он смешивает имена полей со значениями.

Я полагаю, вы возвращаете ответ через конечную точку REST. Я рекомендую Spring IO: Создание веб-службы RESTful , чтобы начать читать о преобразовании в Spring из объекта в JSON (выделяет и редактирует имя объекта самостоятельно):

Объект XXX необходимо преобразовать в JSON. Благодаря поддержке конвертера сообщений HTTP в Spring, вам не нужно выполнять это преобразование вручную. Поскольку Jackson 2 находится на пути к классам, Spring MappingJackson2HttpMessageConverter автоматически выбирается для преобразования экземпляра XXX в JSON.

... в противном случае вы можете использовать Jackson или GSON или любую другую альтернативу вручную ". Это выходит за рамки данного вопроса, и на них уже были даны ответы здесь и здесь . Результат в JSON приведенного выше кода для вашего примера ввода:

{
   "math1":{
      "root":{
         "root1": ["asdf", "2fa"],
         "root2": ["23fasdf"]
      },
      "cosin":{
         "tan1": ["","a"]
      }
   },
   "math2":{
      "sigma":{
         "alt": ["22", "2fa", ""]
      },
      "ak1":{
         "test": ["aaaf3"]
      },
      "ak2":{
         "test2": ["af3vv"]
      }
   }
}
...