Comparer deux objets JSON en Java

je suis à la recherche d'une bibliothèque JSON parsing qui soutient la comparaison de deux objets JSON ignorant commande d'enfant, spécifiquement pour l'Unité de test JSON revenant d'un service web.

est-ce que l'une des principales bibliothèques JSON soutient ceci? Le org.la bibliothèque json fait simplement une comparaison de référence.

176
demandé sur Jordan Stewart 2010-02-12 20:30:00

22 réponses

en tant que point d'architecture général, je déconseille habituellement de laisser les dépendances sur un format de sérialisation particulier se vider de leur substance au-delà de votre couche de stockage/réseau; ainsi, je recommande d'abord que vous envisagiez de tester l'égalité entre vos propres objets d'application plutôt que leurs manifestations JSON.

ayant dit cela, je suis actuellement un grand fan de Jackson qui ma lecture rapide de leur ObjectNode.égal () la mise en œuvre suggère l'appartenance de comparaison que vous voulez:

public boolean equals(Object o)
{
    if (o == this) return true;
    if (o == null) return false;
    if (o.getClass() != getClass()) {
        return false;
    }
    ObjectNode other = (ObjectNode) o;
    if (other.size() != size()) {
        return false;
    }
    if (_children != null) {
        for (Map.Entry<String, JsonNode> en : _children.entrySet()) {
            String key = en.getKey();
            JsonNode value = en.getValue();

            JsonNode otherValue = other.get(key);

            if (otherValue == null || !otherValue.equals(value)) {
                return false;
            }
        }
    }
    return true;
}
65
répondu Jolly Roger 2018-09-25 16:24:43

Essayer Skyscreamer JSONAssert .

Its non-strict le mode présente deux avantages majeurs qui le rendent moins fragile:

  • extensibilité de L'objet (par exemple avec une valeur attendue de {id:1} , cela passerait encore: {id:1,moredata:'x'} .)
  • Lâche tableau de commande (par exemple, ['chien','cat']==['cat','chien'])

en mode strict, il se comporte plus comme la classe test de json-lib.

un test ressemble à quelque chose comme ceci:

@Test
public void testGetFriends() {
    JSONObject data = getRESTData("/friends/367.json");
    String expected = "{friends:[{id:123,name:\"Corby Page\"}"
        + ",{id:456,name:\"Solomon Duskis\"}]}";
    JSONAssert.assertEquals(expected, data, false);
}

les paramètres du JSONAssert.assertEquals() appel sont expectedJSONString , actualDataString , et isStrict .

les messages de résultat sont assez clairs, ce qui est important lorsque l'on compare De Très gros objets JSON.

125
répondu Carter Page 2012-04-06 17:48:23

utilisant GSON

JsonParser parser = new JsonParser();
JsonElement o1 = parser.parse("{a : {a : 2}, b : 2}");
JsonElement o2 = parser.parse("{b : 2, a : {a : 2}}");
assertEquals(o1, o2);
38
répondu axelhzf 2012-01-30 14:20:01

je voudrais faire le suivant,

final JSONObject obj1 = /*json*/;
final JSONObject obj2 = /*json*/;

final ObjectMapper mapper = new ObjectMapper();

final JsonNode tree1 = mapper.readTree(obj1.toString());
final JsonNode tree2 = mapper.readTree(obj2.toString());

return tree1.equals(tree2);
18
répondu joshu 2014-06-11 00:43:15

vous pouvez essayer d'utiliser json-lib's JSONAssert classe:

JSONAssert.assertEquals(
  "{foo: 'bar', baz: 'qux'}",
  JSONObject.fromObject("{foo: 'bar', baz: 'xyzzy'}"));

donne:

junit.framework.ComparisonFailure: objects differed at key [baz]; expected:<[qux]> but was:<[xyzzy]>
11
répondu hertzsprung 2011-05-23 17:56:44

si vous utilisez déjà JUnit, la dernière version utilise maintenant Hamcrest. Il s'agit d'un cadre d'appariement Générique (particulièrement utile pour les tests unitaires) qui peut être étendu pour construire de nouveaux matchers.

il y a une petite bibliothèque open source appelée hamcrest-json avec des correspondances JSON-aware. Il est bien documenté, testé et soutenu. Voici quelques liens utiles:

exemple de code utilisant des objets de la bibliothèque JSON org.json.simple :

Assert.assertThat(
    jsonObject1.toJSONString(),
    SameJSONAs.sameJSONAs(jsonObject2.toJSONString()));

en option, vous pouvez (1) autoriser les tableaux" n'importe quel ordre " et (2) ignorer les champs supplémentaires.

Puisqu'il existe une variété de bibliothèques JSON pour Java ( Jackson , GSON , json-lib , etc.), il est utile que hamcrest-json supporte le texte de JSON( comme java.lang.String ), ainsi que les objets supportant nativement de la bibliothèque JSON de Douglas Crockford org.json .

enfin, si vous n'utilisez pas JUnit, vous pouvez utiliser Hamcrest directement pour les assertions. ( j'ai écrit à ce sujet ici. )

10
répondu kevinarpe 2017-05-23 12:03:06

utilisez cette bibliothèque: https://github.com/lukas-krecan/JsonUnit

Pom:

<dependency>
    <groupId>net.javacrumbs.json-unit</groupId>
    <artifactId>json-unit</artifactId>
    <version>1.5.0</version>
    <scope>test</scope>
</dependency>

IGNORING_ARRAY_ORDER-ignore l'ordre dans les tableaux

assertJsonEquals("{\"test\":[1,2,3]}",
                 "{\"test\":  [3,2,1]}",when(IGNORING_ARRAY_ORDER));
10
répondu chethu 2016-03-17 15:46:01

vous pouvez essayer JsonUnit . Il peut comparer deux objets JSON et signaler des différences. Il est construit sur Jackson.

par exemple

assertJsonEquals("{\"test\":1}", "{\n\"test\": 2\n}");

résultats dans

java.lang.AssertionError: JSON documents are different:
Different value found in node "test". Expected 1, got 2.
9
répondu Lukas 2012-02-11 10:10:24

une chose que j'ai faite et qui fait des Merveilles est de lire les deux objets dans HashMap puis de les comparer avec un assertEquals régulier(). Il appellera la méthode equals () des hashmaps, qui comparera récursivement tous les objets à l'intérieur (ils seront soit d'autres hashmaps ou un objet à une seule valeur comme une chaîne ou un entier). Cela a été fait en utilisant Codehaus ' Jackson JSON parser.

assertEquals(mapper.readValue(expectedJson, new TypeReference<HashMap<String, Object>>(){}), mapper.readValue(actualJson, new TypeReference<HashMap<String, Object>>(){}));

une approche similaire peut être utilisée si L'objet JSON est un tableau à la place.

5
répondu Claudio Aguiar 2011-11-09 15:52:41

pour org.json j'ai déployé ma propre solution, une méthode qui se compare aux instances de JSONObject. Je n'ai pas travaillé avec des objets JSON complexes dans ce projet, donc je ne sais pas si cela fonctionne dans tous les scénarios. De plus, étant donné que je l'utilise dans les tests unitaires, je n'ai pas mis d'effort dans les optimisations. Le voici:

public static boolean jsonObjsAreEqual (JSONObject js1, JSONObject js2) throws JSONException {
    if (js1 == null || js2 == null) {
        return (js1 == js2);
    }

    List<String> l1 =  Arrays.asList(JSONObject.getNames(js1));
    Collections.sort(l1);
    List<String> l2 =  Arrays.asList(JSONObject.getNames(js2));
    Collections.sort(l2);
    if (!l1.equals(l2)) {
        return false;
    }
    for (String key : l1) {
        Object val1 = js1.get(key);
        Object val2 = js2.get(key);
        if (val1 instanceof JSONObject) {
            if (!(val2 instanceof JSONObject)) {
                return false;
            }
            if (!jsonObjsAreEqual((JSONObject)val1, (JSONObject)val2)) {
                return false;
            }
        }

        if (val1 == null) {
            if (val2 != null) {
                return false;
            }
        }  else if (!val1.equals(val2)) {
            return false;
        }
    }
    return true;
}
4
répondu Victor Ionescu 2013-07-11 12:28:18

j'utilise ceci, et fonctionne très bien pour moi (avec org.json.* ):

package com.project1.helpers;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

public class JSONUtils {

    public static boolean areEqual(Object ob1, Object ob2) throws JSONException {
        Object obj1Converted = convertJsonElement(ob1);
        Object obj2Converted = convertJsonElement(ob2);
        return obj1Converted.equals(obj2Converted);
    }

    private static Object convertJsonElement(Object elem) throws JSONException {
        if (elem instanceof JSONObject) {
            JSONObject obj = (JSONObject) elem;
            Iterator<String> keys = obj.keys();
            Map<String, Object> jsonMap = new HashMap<>();
            while (keys.hasNext()) {
                String key = keys.next();
                jsonMap.put(key, convertJsonElement(obj.get(key)));
            }
            return jsonMap;
        } else if (elem instanceof JSONArray) {
            JSONArray arr = (JSONArray) elem;
            Set<Object> jsonSet = new HashSet<>();
            for (int i = 0; i < arr.length(); i++) {
                jsonSet.add(convertJsonElement(arr.get(i)));
            }
            return jsonSet;
        } else {
            return elem;
        }
    }
}
3
répondu catcher 2015-11-13 14:36:36

je prendrais la bibliothèque à http://json.org/java / , et modifier la méthode equals de JSONObject et JSONArray pour faire un test d'égalité profonde. Pour s'assurer que cela fonctionne sans se dégrader de l'ordre des enfants, tout ce que vous devez faire est de remplacer la carte intérieure avec un TreeMap , ou utiliser quelque chose comme Collections.sort() .

2
répondu Yoni 2010-02-12 17:58:56

essayez ceci:

public static boolean jsonsEqual(Object obj1, Object obj2) throws JSONException

    {
        if (!obj1.getClass().equals(obj2.getClass()))
        {
            return false;
        }

        if (obj1 instanceof JSONObject)
        {
            JSONObject jsonObj1 = (JSONObject) obj1;

            JSONObject jsonObj2 = (JSONObject) obj2;

            String[] names = JSONObject.getNames(jsonObj1);
            String[] names2 = JSONObject.getNames(jsonObj1);
            if (names.length != names2.length)
            {
                return false;
            }

            for (String fieldName:names)
            {
                Object obj1FieldValue = jsonObj1.get(fieldName);

                Object obj2FieldValue = jsonObj2.get(fieldName);

                if (!jsonsEqual(obj1FieldValue, obj2FieldValue))
                {
                    return false;
                }
            }
        }
        else if (obj1 instanceof JSONArray)
        {
            JSONArray obj1Array = (JSONArray) obj1;
            JSONArray obj2Array = (JSONArray) obj2;

            if (obj1Array.length() != obj2Array.length())
            {
                return false;
            }

            for (int i = 0; i < obj1Array.length(); i++)
            {
                boolean matchFound = false;

                for (int j = 0; j < obj2Array.length(); j++)
                {
                    if (jsonsEqual(obj1Array.get(i), obj2Array.get(j)))
                    {
                        matchFound = true;
                        break;
                    }
                }

                if (!matchFound)
                {
                    return false;
                }
            }
        }
        else
        {
            if (!obj1.equals(obj2))
            {
                return false;
            }
        }

        return true;
    }
1
répondu Misha 2014-02-11 14:25:58

vous pouvez utiliser zjsonpatch bibliothèque, qui présente les informations diff conformément à la RFC 6902 (JSON Patch). Il est très facile à utiliser. S'il vous plaît visitez sa page de description pour son usage

1
répondu z31415 2015-07-09 14:18:28

je sais qu'il est généralement considéré uniquement pour les tests, mais vous pourriez utiliser le Hamcrest JSON comparitorSameJSONAs dans Hamcrest JSON.

Hamcrest JSON SameJSONAs

1
répondu Justin Ohms 2016-09-27 17:59:15

Pour ceux comme moi qui veulent le faire avec Jackson, vous pouvez utiliser json-unité .

JsonAssert.assertJsonEquals(jsonNode1, jsonNode2);

Les erreurs de donner une rétroaction utile sur le type de décalage:

java.lang.AssertionError: JSON documents have different values:
Different value found in node "heading.content[0].tag[0]". Expected 10209, got 10206.
0
répondu krookedking 2014-09-24 17:18:27

Karaté est exactement ce que vous recherchez. Voici un exemple:

* def myJson = { foo: 'world', hey: 'ho', zee: [5], cat: { name: 'Billie' } }
* match myJson = { cat: { name: 'Billie' }, hey: 'ho', foo: 'world', zee: [5] }

(avertissement: dev ici)

0
répondu Peter Thomas 2017-02-25 04:04:09

rien d'autre ne semblait fonctionner correctement, alors j'ai écrit ceci:

private boolean jsonEquals(JsonNode actualJson, JsonNode expectJson) {
    if(actualJson.getNodeType() != expectJson.getNodeType()) return false;

    switch(expectJson.getNodeType()) {
    case NUMBER:
        return actualJson.asDouble() == expectJson.asDouble();
    case STRING:
    case BOOLEAN:
        return actualJson.asText().equals(expectJson.asText());
    case OBJECT:
        if(actualJson.size() != expectJson.size()) return false;

        Iterator<String> fieldIterator = actualJson.fieldNames();
        while(fieldIterator.hasNext()) {
            String fieldName = fieldIterator.next();
            if(!jsonEquals(actualJson.get(fieldName), expectJson.get(fieldName))) {
                return false;
            }
        }
        break;
    case ARRAY:
        if(actualJson.size() != expectJson.size()) return false;
        List<JsonNode> remaining = new ArrayList<>();
        expectJson.forEach(remaining::add);
        // O(N^2)   
        for(int i=0; i < actualJson.size(); ++i) {
            boolean oneEquals = false;
            for(int j=0; j < remaining.size(); ++j) {
                if(jsonEquals(actualJson.get(i), remaining.get(j))) {
                    oneEquals = true;
                    remaining.remove(j);
                    break;
                }
            }
            if(!oneEquals) return false;
        }
        break;
    default:
        throw new IllegalStateException();
    }
    return true;
}
0
répondu Alex R 2018-04-13 04:31:02

code suivant sera plus utile pour comparer deux JsonObject, JsonArray, JsonPrimitive et JasonElements.

private boolean compareJson(JsonElement json1, JsonElement json2) {
        boolean isEqual = true;
        // Check whether both jsonElement are not null
        if (json1 != null && json2 != null) {

            // Check whether both jsonElement are objects
            if (json1.isJsonObject() && json2.isJsonObject()) {
                Set<Entry<String, JsonElement>> ens1 = ((JsonObject) json1).entrySet();
                Set<Entry<String, JsonElement>> ens2 = ((JsonObject) json2).entrySet();
                JsonObject json2obj = (JsonObject) json2;
                if (ens1 != null && ens2 != null) {
                    // (ens2.size() == ens1.size())
                    // Iterate JSON Elements with Key values
                    for (Entry<String, JsonElement> en : ens1) {
                        isEqual = isEqual && compareJson(en.getValue(), json2obj.get(en.getKey()));
                    }
                } else {
                    return false;
                }
            }

            // Check whether both jsonElement are arrays
            else if (json1.isJsonArray() && json2.isJsonArray()) {
                JsonArray jarr1 = json1.getAsJsonArray();
                JsonArray jarr2 = json2.getAsJsonArray();
                if (jarr1.size() != jarr2.size()) {
                    return false;
                } else {
                    int i = 0;
                    // Iterate JSON Array to JSON Elements
                    for (JsonElement je : jarr1) {
                        isEqual = isEqual && compareJson(je, jarr2.get(i));
                        i++;
                    }
                }
            }

            // Check whether both jsonElement are null
            else if (json1.isJsonNull() && json2.isJsonNull()) {
                return true;
            }

            // Check whether both jsonElement are primitives
            else if (json1.isJsonPrimitive() && json2.isJsonPrimitive()) {
                if (json1.equals(json2)) {
                    return true;
                } else {
                    return false;
                }
            } else {
                return false;
            }
        } else if (json1 == null && json2 == null) {
            return true;
        } else {
            return false;
        }
        return isEqual;
    }
0
répondu Radadiya Nikunj 2018-04-18 19:00:34

pour comparer les jsons je recommande d'utiliser JSON-compare: https://github.com/fslev/json-compare

// Compare by regex
String expected = "{\"a\":\".*me.*\"}";
String actual = "{\"a\":\"some text\"}";
JSONCompare.assertEquals(expected, actual);  // True

// Check expected array has no extra elements
String expected = "[1,\"test\",4,\"!.*\"]";
String actual = "[4,1,\"test\"]";
JSONCompare.assertEquals(expected, actual);  // True

// Check expected array has no numbers
String expected = "[\"\\\d+\"]";
String actual = "[\"text\",\"test\"]";
JSONCompare.assertEquals(expected, actual);  // True

// Check expected array has no numbers
String expected = "[\"\\\d+\"]";
String actual = "[2018]";
JSONCompare.assertNotEquals(expected, actual);  // True
0
répondu Slev Florin 2018-06-12 19:27:21
JSON.areEqual(json1, json2); //using BlobCity Java Commons

https://tech.blobcity.com/2018/09/02/json-equals-in-java-to-compare-two-jsons

0
répondu Sanket Sarang 2018-09-05 18:38:44

Cette Solution pour moi, le travail est très bon:

try {           
                // Getting The Array "Courses" from json1 & json2   
                Courses1 =json1.getJSONArray(TAG_COURSES1);
                Courses2 = json2.getJSONArray(TAG_COURSES);

                //LOOP FOR JSON1
                for(int i = 0; i < Courses1.length(); i++){
                    //LOOP FOR JSON2
                    for(int ii = 0; ii < Courses2.length(); ii++){
                        JSONObject courses1 = Courses1.getJSONObject(i);
                        JSONObject courses2 = Courses2.getJSONObject(ii);

                        // Storing each json1 item in variable
                        int courseID1 = courses1.getInt(TAG_COURSEID1);
                        Log.e("COURSEID2:", Integer.toString(courseID1));
                        String Rating1 = courses1.getString(TAG_RATING1);
                        int Status1 = courses1.getInt(TAG_STATUS1);
                        Log.e("Status1:", Integer.toString(Status1));      //Put the actual value for Status1 in log.             

                        // Storing each json2 item in variable
                        int courseID2 = courses2.getInt(TAG_COURSEID);
                        Log.e("COURSEID2:", Integer.toString(courseID));   //Put the actual value for CourseID in log
                        String Title2 = courses2.getString(TAG_TITLE);                      
                        String instructor2 = courses2.getString(TAG_INSTRUCTOR);
                        String length2 = courses2.getString(TAG_LENGTH);
                        String rating2 = courses2.getString(TAG_RATING);
                        String subject2 = courses2.getString(TAG_SUBJECT);
                        String description2 = courses2.getString(TAG_DESCRIPTION);

                        //Status1 = 5 from json1; Incomplete, Status1 =-1 Complete 
                        if(Status1 == 5 && courseID2 == courseID1){                                  

                        // creating new HashMap
                        HashMap<String, String> map = new HashMap<String, String>();         
                        //Storing the elements if condition is true.
                        map.put(TAG_COURSEID, Integer.toString(courseID2)); //pend for compare
                        map.put(TAG_TITLE, Title2);
                        map.put(TAG_INSTRUCTOR, instructor2);
                        map.put(TAG_LENGTH, length2);
                        map.put(TAG_RATING, rating2);
                        map.put(TAG_SUBJECT, subject2); //show it
                        map.put(TAG_DESCRIPTION, description2);

                        //adding HashList to ArrayList
                        contactList.add(map);
                        }//if
                    }//for2 (json2)
                } //for1 (json1)                
            }//Try

Espérons que cela aide les autres.

-4
répondu JLouis 2012-05-05 20:44:18