การทดสอบอ็อบเจ็กต์ JSON สองรายการเพื่อดูความเท่าเทียมกันโดยไม่สนใจลำดับย่อยใน Java


233

ฉันกำลังมองหาไลบรารีการแยกวิเคราะห์ JSON ที่สนับสนุนการเปรียบเทียบวัตถุ JSON สองรายการโดยไม่สนใจลำดับลูกโดยเฉพาะสำหรับการทดสอบหน่วย JSON ที่กลับมาจากบริการบนเว็บ

ไลบรารี JSON หลักใด ๆ สนับสนุนสิ่งนี้หรือไม่? ไลบรารี org.json ทำการเปรียบเทียบการอ้างอิงเท่านั้น


1
ไม่สามารถทำให้วัตถุทั้งสองเป็นอนุกรมและเปรียบเทียบสตริงได้หรือไม่ ฉันเดาว่าไลบรารีทั้งหมดสนับสนุนtoString()การแปลงวัตถุเป็นJSONสตริง
Teja Kantamneni

47
ที่ถือว่าลำดับในการอนุกรมและจากสตริงเสมอกัน ฉันไม่สบายใจที่จะตั้งสมมติฐานดังกล่าว
Jeff

คุณพูดถูกเจฟฟ์ไม่ปลอดภัยเลย การทดสอบนี้แสดงให้เห็นถึงสถานการณ์ที่แมปจะเหมือนกัน แต่ toString () ไม่ส่งกลับผลลัพธ์เดียวกัน: gist.github.com/anonymous/5974797 นี่เป็นเพราะ HashMap พื้นฐานนั้นสามารถเติบโตได้และหากคุณลบกุญแจออกอาร์เรย์ภายใน HashMap จะไม่ย่อขนาดลง
Guillaume Perrot

คำตอบ:


84

ในฐานะที่เป็นจุดสถาปัตยกรรมทั่วไปฉันมักจะแนะนำให้ปล่อยให้การพึ่งพารูปแบบการทำให้เป็นอนุกรมโดยเฉพาะมีเลือดออกเกินระดับการจัดเก็บ / เครือข่ายของคุณ ดังนั้นก่อนอื่นฉันขอแนะนำให้คุณพิจารณาการทดสอบความเท่าเทียมกันระหว่างแอปพลิเคชันวัตถุของคุณเองมากกว่าการแสดงออกของ JSON

ต้องบอกว่าตอนนี้ฉันเป็นแฟนตัวยงของแจ็กสันซึ่งการอ่านอย่างรวดเร็วของฉันเกี่ยวกับการใช้งานObjectNode.equals ()แสดงให้เห็นว่าการเปรียบเทียบการเป็นสมาชิกชุดที่คุณต้องการ:

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;
}

วิธีนี้ไม่ได้สมมาตรเนื่องจากเป็นการทดสอบความสัมพันธ์ 'เซตย่อย' ของเด็กเท่านั้นไม่ใช่ความเท่าเทียมกัน วัตถุ 'อื่น ๆ ' อาจมีเด็กมากกว่านั้นใน _children และวิธีนี้จะยังคงกลับมาจริง
Yoni

23
@Yoni: ไม่เป็นความจริงเนื่องจากมีการเปรียบเทียบขนาด พวกเขาจะต้องมีจำนวนลูกที่แน่นอนเช่นเดียวกับเด็กคนเดียวกัน @ Jolly Roger: ในกรณีนี้ฉันไม่ได้จัดลำดับวัตถุจาก JSON กลับเป็น POJO แต่เมื่อส่ง JSON ระบบที่ทำฉันไม่สามารถพึ่งพามันได้ส่งรูปแบบเดียวกันกับที่ฉันส่งไป มัน.
Jeff

1
@Jeff สิ่งนี้ทำงานให้คุณได้ไหม? ใน Junit assertEquals ล้มเหลวสำหรับฉัน โครงการกำลังใช้เวอร์ชันเก่า (1.5), fyi
ronnyfm

1
ฉันคิดว่าคุณขาดการทดสอบระดับสูงหากคุณไม่ยืนยัน JSON คุณสามารถทดสอบบางอย่างซึ่งทำให้คำขอ http และตอบสนองกับ JSON ที่คาดหวัง - มันเป็นพฤติกรรมการทำงานหลักของบริการเว็บ
mogronalol

เพียงโน้ตเล็กน้อยเกี่ยวกับประสิทธิภาพ: รหัสที่เปรียบเทียบ 'value' กับ 'otherValue' สามารถทำให้ง่ายขึ้นถ้า (value.equals (other.get (key)) คืนค่า false เนื่องจาก 'value' รับประกันว่าจะไม่เป็นโมฆะและ วิธีการเท่าเทียมกันของ JsonNode () ควรยอมรับอาร์กิวเมนต์ที่เป็นโมฆะ
Tillmann

154

ลอง SkyScreamer ของJSONAssert

มันไม่ใช่อย่างเข้มงวดโหมดมีสองข้อได้เปรียบที่สำคัญที่จะทำให้มันเปราะน้อย:

  • ความสามารถในการขยายออบเจ็กต์ (เช่นด้วยค่าที่คาดหวังของ{id: 1}สิ่งนี้จะยังคงผ่าน: {id: 1, moredata: 'x'} )
  • การเรียงลำดับแบบหลวม ๆ (เช่น ['dog', 'cat'] == ['cat', 'dog'])

ในโหมดเข้มงวดจะทำงานเหมือนคลาสทดสอบของ json-lib

การทดสอบมีลักษณะดังนี้:

@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);
}

พารามิเตอร์ในการเรียก JSONAssert.assertEquals () คือ expectedJSONString , actualDataStringและisStrict

ข้อความผลลัพธ์ค่อนข้างชัดเจนซึ่งเป็นสิ่งสำคัญเมื่อเปรียบเทียบออบเจ็กต์ JSON ขนาดใหญ่จริง ๆ


18
ฉันใช้โซลูชันนี้ แต่ฉันเพิ่งพบว่าคุณสามารถระบุ JSONCompareMode ที่คุณเลือกได้ หนึ่งในนั้นคือ NON_EXTENSIBLE ดังนั้นคุณจะมีสิ่งนี้: JSONAssert.assertEquals(expected, data, JSONCompareMode.NON_EXTENSIBLE);โหมด NON_EXTENSIBLE หมายความว่าฟิลด์ใหม่หรือฟิลด์ที่หายไปทำให้เกิดความล้มเหลว แต่การสั่งซื้อไม่ได้ การใช้ false จะทำให้เกิดโหมดผ่อนปรนซึ่งจะไม่รายงานองค์ประกอบลูก ๆ เพิ่มเติมหรือขาดหายไป
ด่านวัด

1
โหมดเปรียบเทียบ NON_EXTENSIBLE เป็นว่าสิ่งที่ผมกำลังมองหา ขอบคุณสำหรับสิ่งนี้แดน
ThoughtCrhyme

ก่อนที่ฉันจะรู้สึกตื่นเต้นทั้งหมด: สิ่งนี้สนับสนุนวัตถุและอาร์เรย์ JSON ซ้อนกันหรือไม่ :)
Christian

2
ผู้ใช้อาจต้องการพิจารณาปัญหา JSONassert นี้ก่อนที่จะใช้ไลบรารี: เป็นการระบุว่าขณะนี้มีปัญหาด้านลิขสิทธิ์ที่อาจเกิดขึ้นกับการขึ้นต่อกันของไลบรารี
Chriki

3
แก้ไขปัญหา JSONAssert # 44 ด้วยการเปลี่ยนไลบรารี clean-room ใน PR 67 ซึ่งเปิดตัวในวันนี้เป็น JSONAssert 1.4.0
คาร์เตอร์หน้า

49

ใช้ 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);

แก้ไข: ตั้งแต่GSON v2.8.6วิธีการเช่นJsonParser.parseนั้นเลิกใช้แล้ว คุณต้องใช้วิธีการคงที่JsonParser.parseString:

JsonElement o1 = JsonParser.parseString("{a : {a : 2}, b : 2}");
JsonElement o2 = JsonParser.parseString("{b : 2, a : {a : 2}}");
assertEquals(o1, o2);

ทำงานใน GSON 2.8.2 สำหรับฉัน
Tom Saleeba

1
มันไม่ทำงานหากองค์ประกอบ jsonArray ไม่เป็นไปตามลำดับ รุ่น 2.8.2
Naveen Kumar RB

1
ไม่ทำงานสำหรับฉันหากลำดับของวัตถุ / องค์ประกอบแตกต่างกัน
Jknair

มันใช้งานได้สำหรับฉันเพราะฉันแค่ต้องการทดสอบหน่วยที่คุณสมบัติ jsons ทั้งสองมีคำสั่งเดียวกัน
GabrielBB

@GabrielBB คุณควรแก้ไขคำถามและระบุว่าเวอร์ชันใดที่ API ไม่ได้รับการสนับสนุนและรูปแบบใหม่ของรหัสเริ่มทำงาน
clearlight

30

ฉันจะทำต่อไปนี้

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

ObjectMapper mapper = new ObjectMapper();

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

return tree1.equals(tree2);

หากคุณใช้งาน Jackson อยู่นี่เป็นคำตอบที่ดีที่สุดสำหรับ IMHO
Christoph Dietze

18
แต่นี่เป็นการเปรียบเทียบที่เข้มงวดฉันคิดว่า มันจะคืนค่าเท็จสำหรับ json สองตัวที่เท่ากันซึ่งมีลำดับองค์ประกอบต่างกัน
deadpool

@deadpool หลักการคือเสียงคุณเพียงแค่ต้องเปลี่ยนการเปรียบเทียบเพื่อให้มีส่วนร่วมมากขึ้น (ตรวจสอบเขตข้อมูลที่สำคัญเช่นแทนที่จะเป็นง่ายๆเท่ากับต้นไม้)
jwenting

นี่เป็นคำตอบที่ดีที่สุด ไม่เพียง แต่จะตอบคำถามของฉันในขณะนี้ แต่ยังตอบทุกการเปรียบเทียบออบเจกต์ที่เราต้องทำ ขอบคุณ joshu
Luiz Feijão Veronesi

2
@deadpool อาจเป็นการเปรียบเทียบที่เข้มงวด แต่ตอนนี้ยังไม่เข้มงวด
Andrei Damian-Fekete

18

คุณสามารถลองใช้คลาสJSONAssertของ json-lib :

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

ให้:

junit.framework.ComparisonFailure: objects differed at key [baz]; expected:<[qux]> but was:<[xyzzy]>

หรือง่ายยิ่งขึ้น: JSONAssert.assertJsonEquals ("{foo: 'bar', baz: 'qux'}", {foo: 'bar', baz: 'xyzzy'} ");
Rob Juurlink

2
ในขณะที่วิธีนี้ใช้ได้ผลกับลำดับของรายการข้อมูลภายใน JSON มันจะล้มเหลวหากลำดับขององค์ประกอบภายในอาร์เรย์ไม่ตรงกัน หากรหัสของคุณใช้ชุดที่ถูกแปลงเป็น JSON เช่น การเปรียบเทียบ JSON ต่อไปนี้จะล้มเหลวJSONAssert.assertJsonEquals( "{foo: 'bar', list: [{test: '1'}, {rest: '2'}] }", "{ foo: 'bar', list: [{rest: '2'}, {test: '1'}] }"); ด้วยข้อความ:junit.framework.AssertionFailedError: : : objects differed at key [list];: arrays first differed at element [0];: objects differed at key [test];
Dan Temple

ใช่นี่เป็นข้อ จำกัด ของ Json :(. json.org แสดงให้เห็นว่าไม่มีโทเค็นของคอลเลกชันที่ไม่ได้เรียงลำดับ {} สามารถล้อมคู่คู่ของคีย์ - ค่าได้เท่านั้นนี่เป็นสิ่งที่น่ารำคาญอย่างมาก
Merk

15

ใช้ไลบรารีนี้: 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 - ละเว้นคำสั่งในอาร์เรย์

assertJsonEquals("{\"test\":[1,2,3]}",
  "{\"test\":  [3,2,1]}",
  when(IGNORING_ARRAY_ORDER)
);

คุณสามารถเพิ่มความคิดเห็นเพิ่มเติมเกี่ยวกับวิธีที่เราสามารถใช้มันฉันเพิ่มเข้าไป pom ของฉัน แต่เราต้อง doc เพื่อให้เข้าใจวิธีการใช้งาน
Ran แอดเลอร์

การใช้งานง่ายมาก: เพิ่มไปยัง pom ของคุณ <dependency> <groupId> net.javacrumbs.json-unit </groupId> <artifactId> json-unit </artifactId> <version> 1.5.0 </version> <scope> </scope> </dependency>
chethu

10x ฉันได้มองไปที่การเรียนการสอนที่เชื่อมโยงและฉันพบว่ามัน :)
Ran Adler

12

หากคุณใช้ JUnit อยู่แล้วเวอร์ชันล่าสุดจะใช้ Hamcrest เป็นกรอบการจับคู่ทั่วไป (มีประโยชน์อย่างยิ่งสำหรับการทดสอบหน่วย) ที่สามารถขยายเพื่อสร้าง matchers ใหม่

มีไลบรารีโอเพนซอร์สขนาดเล็กที่เรียกว่าตรงhamcrest-jsonกับ JSON-aware มันเป็นเอกสารที่ดีทดสอบและรองรับ ลิงค์ด้านล่างนี้มีประโยชน์:

โค้ดตัวอย่างที่ใช้วัตถุจากไลบรารี JSON org.json.simple:

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

คุณสามารถเลือกที่จะ (1) อนุญาตอาร์เรย์ "any-order" และ (2) ละเว้นฟิลด์พิเศษ

เนื่องจากมีความหลากหลายของห้องสมุด JSON สำหรับ Java ( Jackson, GSON, json-libฯลฯ ) จะเป็นประโยชน์ที่hamcrest-jsonสนับสนุน JSON ข้อความ (เป็นjava.lang.String) org.jsonเช่นเดียวกับการกำเนิดสนับสนุนวัตถุจากห้องสมุด

สุดท้ายหากคุณไม่ได้ใช้ JUnit คุณสามารถใช้ Hamcrest โดยตรงเพื่อยืนยัน ( ฉันเขียนถึงที่นี่ )


อะไรคือข้อดีของการใช้ hamcrast matchers แทนที่จะใช้ JSONAssert โดยตรง
Johannes

2
@Johannes: สไตล์เท่านั้น
kevinarpe

แหล่งข้อมูล hamcrest-json ปัจจุบันมีวันที่ส่งมอบครั้งสุดท้ายในปี 2555 อาจไม่ได้รับการสนับสนุนเป็นอย่างดีอีกต่อไป
Thorbjørn Ravn Andersen

11

คุณสามารถลองJsonUnit มันสามารถเปรียบเทียบวัตถุ JSON สองรายการและรายงานความแตกต่าง มันสร้างขึ้นที่ด้านบนของแจ็คสัน

ตัวอย่างเช่น

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

ผลลัพธ์ใน

java.lang.AssertionError: JSON documents are different:
Different value found in node "test". Expected 1, got 2.

6

สิ่งหนึ่งที่ฉันทำและใช้งานได้ดีคือการอ่านวัตถุทั้งสองลงใน HashMap แล้วเปรียบเทียบกับ assertEquals ปกติ () มันจะเรียกวิธีการเท่ากับ () ของ hashmaps ซึ่งจะเปรียบเทียบวัตถุทั้งหมดภายในซ้ำ (พวกเขาจะเป็น hashmaps อื่น ๆ หรือวัตถุค่าเดียวบางอย่างเช่นสตริงหรือจำนวนเต็ม) สิ่งนี้ทำโดยใช้เครื่องมือแยกวิเคราะห์ Jackson JSON ของ Codehaus

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

วิธีการที่คล้ายกันสามารถนำมาใช้ถ้าวัตถุ JSON เป็นอาร์เรย์แทน


6

ฉันใช้สิ่งนี้และทำงานได้ดีสำหรับฉัน (with 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;
        }
    }
}

4

สำหรับ org.json ฉันได้เผยแพร่โซลูชันของฉันเองแล้ววิธีการเปรียบเทียบกับอินสแตนซ์ JSONObject ฉันไม่ได้ทำงานกับวัตถุ JSON ที่ซับซ้อนในโครงการนั้นดังนั้นฉันจึงไม่ทราบว่าสิ่งนี้ใช้ได้ในทุกสถานการณ์หรือไม่ นอกจากนี้เนื่องจากฉันใช้สิ่งนี้ในการทดสอบหน่วยฉันไม่ได้ใช้ความพยายามในการปรับปรุง นี่มันคือ:

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;
}

1
เนื่องจากคุณกล่าวถึงการปรับให้เหมาะสม :) หากval1เป็นโมฆะคุณจะได้รับ NullPointerException จากรหัสนี้if (!val1.equals(val2)) {
JohnDoDo

มันเกิดขึ้นกับสิ่งที่ดีที่สุดของเราด้วย :) +1 สำหรับการแก้ไขในคำตอบของคุณ
JohnDoDo

ชี้ไปที่ :) หวังว่ามันจะไม่ได้รับคะแนนมากเกินไปมิฉะนั้นมันจะได้รับการสนับสนุนมากมาย
Victor Ionescu

1
คุณไม่ได้พิจารณาว่าjs2จะเป็นnullเมื่อไหร่หรือjs1ไม่null
Xiao

รหัสนี้ใช้ไม่ได้กับวัตถุ / ลำดับที่ซ้อนกัน
FabienB

3

คุณสามารถใช้ไลบรารีzjsonpatchซึ่งแสดงข้อมูล diff ตาม RFC 6902 (JSON Patch) มันใช้งานง่ายมาก กรุณาเยี่ยมชมหน้าคำอธิบายสำหรับการใช้งาน


2

ฉันใช้ห้องสมุดที่http://json.org/java/และปรับเปลี่ยนequalsวิธีการของ JSONObject และ JSONArray เพื่อทำการทดสอบความเท่าเทียมกันอย่างลึกซึ้ง เพื่อให้แน่ใจว่ามันจะทำงานได้อย่างไร้ระเบียบตามคำสั่งของเด็ก ๆ สิ่งที่คุณต้องทำคือแทนที่แผนที่ด้านในด้วยTreeMapหรือใช้อะไรทำนองCollections.sort()นั้น


4
มันไม่ค่อยดีนัก - มันควรจะมาพร้อมกับ code เพื่อทำการเปรียบเทียบ json
Chii

แต่ลองนึกภาพการเขียนรหัสที่ JSON สามารถเป็นอะไรก็ได้ในโครงสร้างใด ๆ ... เขียนเปรียบเทียบกับที่! มันเหมือนกับการเขียนเปรียบเทียบสำหรับทุกหน้า HTML ประเภท
JPM

2

ลองสิ่งนี้:

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;
    }

ภายใน jsonArrays สิ่งนี้จะคืนค่าเป็นจริงหากองค์ประกอบบางอย่างเกิดขึ้นพร้อมกันซึ่งตรงข้ามกับองค์ประกอบทั้งหมดที่ตรงกัน
matiasg

@matiasg - if (obj1Array.length() != obj2Array.length())ไม่แน่ใจว่าองค์ประกอบทั้งหมดตรงกันหรือไม่
kwah

3
@kwah: ไม่ ลองพิจารณาตัวอย่างนี้: obj1Array = [1,1,1], obj2Array = [1,2,3] สิ่งนี้จะกลับมาจริง นอกจากนี้แม้ว่าองค์ประกอบตรงกันพวกเขาควรอยู่ในลำดับเดียวกัน สิ่งนี้จะกลับมาเป็นจริงสำหรับ [1,2,3] และ [2,3,1] ด้วยซึ่งเป็นสิ่งที่ผิด
matiasg


2

คาราเต้เป็นสิ่งที่คุณกำลังมองหา นี่คือตัวอย่าง:

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

(ข้อจำกัดความรับผิดชอบ: dev ที่นี่)


2

สำหรับการเปรียบเทียบ jsons ฉันแนะนำให้ใช้ JSONCompare: 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

สำหรับคนอย่างฉันที่อยากจะทำกับแจ็คสันคุณสามารถใช้หน่วย jsonได้

JsonAssert.assertJsonEquals(jsonNode1, jsonNode2);

ข้อผิดพลาดให้ข้อเสนอแนะที่เป็นประโยชน์กับประเภทของการไม่ตรงกัน:

java.lang.AssertionError: JSON documents have different values:
Different value found in node "heading.content[0].tag[0]". Expected 10209, got 10206.

0

ดูเหมือนจะไม่มีอะไรทำงานได้ค่อนข้างถูกต้องดังนั้นฉันจึงเขียนสิ่งนี้:

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

รหัสต่อไปนี้จะมีประโยชน์มากขึ้นในการเปรียบเทียบ JsonObject สองรายการ, JsonArray, JsonPrimitive และ 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

ดูคำตอบฉันลอง JSONAssert แต่มันล้มเหลว ดังนั้นฉันจึงใช้แจ็คสันกับ zjsonpatch ผมโพสต์รายละเอียดในคำตอบของกลุ่ม SO ที่นี่


-5

โซลูชันนี้สำหรับฉันทำงานได้ดีมาก:

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

หวังว่าสิ่งนี้จะช่วยผู้อื่น


แน่นอนเพียงแค่ใส่ค่าและเงื่อนไขของคุณและชนิดของมุมมองในกรณีนี้ Hashmap เหนือ listview
JLouis

1
นี่เป็นตัวอย่างที่ดีสำหรับวิธีที่จะไม่ทำ :)
Petr Újezdský
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.