t.me/atinfo_chat Telegram группа по автоматизации тестирования

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

Теги: #<Tag:0x00007f9aff2e5ee0> #<Tag:0x00007f9aff2e5968> #<Tag:0x00007f9aff2e5738>

Как сравнить два джейсона, например
[{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 (которые могут различаться).

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

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

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

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

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

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

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

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

1 Симпатия

То есть я смогу как то просто вычесть из одного 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]}

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

// 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. Json можно конвертнуть в java-объекты и сравнивать потом уже их. Например, как-то так:

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

Jackson
ReflectionAssert

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

JsonUnit