Есть отличная удаленная работа для php+codeception+jenkins+allure+docker спецов. 100% remote! Присоединиться к проекту

Как сравнить два json на совпадающие, лишние и недостающие элементы? В идеале в groovy или java

soapui
groovy
java
Теги: #<Tag:0x00007f7b65919a78> #<Tag:0x00007f7b659197f8> #<Tag:0x00007f7b659196b8>

(Tatyana Durova) #1

Как сравнить два джейсона, например
[{id:5, color:red}, {id:8, color:blue}{id:9, color:blue}{id:2, color:green}] и {[id:2, status:1], [id:8, status:2],[id:100, status:1]}

Ожидаю что-то такое:
Совпадает 2 элемента, с id=2 и id=8.
Не найдены элементы: id = 5, id = 9
Недостающие элементы: id:100.

То есть мне нужна полная разница между двумя json объектами по id, при этом сортировки по id нет, и у каждого элемента есть еще другие параметры кроме id (которые могут различаться).


(Александр Таранков) #2

Готового решения нет, надо писать код, который будет проводить сравнение по требуемому алгоритму:

  1. прочитать JSON-объекты в Java-объект (или в мап, сортированный список и т.д., с чем удобнее работать)
  2. сравнить полученные объекты

(Sergey Korol) #3

На основании каких правил мы должны определять степень соответствия элементов, или их отсутствия?
Из ваших примеров и ожиданий слабо прослеживается хоть какая-то нить:

  • Каким образом отсюда следует, что они совпадают? У них разные цвета и статусы. Или имеется ввиду их наличие в обоих массивах?
  • Не найдены где? Во втором массиве? Тогда так и указывайте, что приоритет поиска - вхождение элементов с id первого массива во второй.
  • Опять-таки, недостающие где? В первом массиве?

Что-то я совсем потерял суть. В любом случае вам придется создавать POJO, характеризующий оригинальный объект для сравнения. Далее читаете респонс в массив из этих самых POJO и пишете кастомные comparators на основании той логики, которая вам нужна. В Java 8 можно достаточно просто стримом пройтись по коллекции и отфильтровать объекты по заданному кастомному comparator’у.


(Tatyana Durova) #4

Нет, различия там могут быть в элементах, но везде есть один неизменный атрибут - id. Хотелось бы сравнить только по нему, остальные как раз надо как то игнорировать.


(Tatyana Durova) #5

А нельзя как то использовать коллекции например… может есть какие то библиотеки с такими методами…?


(Павел Ветохин) #6

Можно сконвертировать при помощи jackson в коллекцию maps или объектов определенного типа. Затем сравнить 2 коллекции при помощи ReflectionAssert из unitils.


(Tatyana Durova) #7

То есть я смогу как то просто вычесть из одного json второй? Типа

Example:
json1:[{id:5, color:red}, {id:8, color:blue}{id:9, color:blue}{id:2, color:green}]
json2:{[id:2, status:1], [id:8, status:2],[id:100, status:1]}

surplus json1 - json2 by id= [{id:5, color:red}, {id:9, color:blue}]
surplus json2 - json1 by id= {[id:100, status:1]}


(Sergey Korol) #8

Если вам нужна лишь разница, то как-то так:

// POJO
pulbic class MyPojo {
    private Integer id;
    private Integer status;
    private String color;

    /// getters + toString()
}
// Read json into collection
Gson gson = new Gson();
Type listType = new TypeToken<ArrayList<MyPojo>>(){}.getType();

List<MyPojo> firstPojo = gson.fromJson(firstJsonString, listType);
List<MyPojo> secondPojo = gson.fromJson(secondJsonString, listType);

Дальше, можно вычитать id из обоих коллекций, к примеру, в Set:

Set<Integer> firstSetOfIds = firstPojo.stream().map(MyPojo::getId).collect(toSet());
Set<Integer> secondSetOfIds = secondPojo.stream().map(MyPojo::getId).collect(toSet());

Удаляем вхождения второго в первый и смотрим результат:

firstSetOfIds.removeAll(secondSetOfIds);

firstSetOfIds.stream()
    .forEach(id -> firstPojo.stream()
        .filter(pojo -> pojo.getId().equals(id))
        .forEach(System.out::println));

По аналогии можно посчитать обратную разницу.

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


Как проверить, что элементы в json отсортированы по конкретному признаку?
(Павел Ветохин) #9

Лучше не работать непосредственно с json. Json можно конвертнуть в java-объекты и сравнивать потом уже их. Например, как-то так:

List<MyPojo> actual = mapper.readValue(json, new TypeReference<List<MyPojo>>() {});
assertReflectionEquals(expected, actual, LENIENT_ORDER);

Jackson
ReflectionAssert


(Sergey Pirogov) #10

Есть же всякие JSONAsertions


(rasp23) #11

JsonUnit