When both the objects are JSON Arrays, you are just comparing according to position of JSON objects, please find below code for correct at code,
else if (jsonElement1.isJsonArray() && jsonElement2.isJsonArray()) {
JsonArray jarr1 = jsonElement1.getAsJsonArray();
JsonArray jarr2 = jsonElement2.getAsJsonArray();
if (jarr1.size() != jarr2.size()) {
return false;
} else {
// Iterate JSON Array to JSON Elements
for (JsonElement je1 : jarr1) {
boolean flag = false;
for(JsonElement je2 : jarr2){
flag = compareJson(je1, je2);
if(flag){
jarr2.remove(je2);
break;
}
}
isEqual = isEqual && flag;
}
}
}
Answer from Rajani B on Stack OverflowVideos
Try Skyscreamer's JSONAssert.
Its non-strict mode has two major advantages that make it less brittle:
- Object extensibility (e.g. With an expected value of {id:1}, this would still pass: {id:1,moredata:'x'}.)
- Loose array ordering (e.g. ['dog','cat']==['cat','dog'])
In strict mode it behaves more like json-lib's test class.
A test looks something like this:
@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);
}
The parameters in the JSONAssert.assertEquals() call are expectedJSONString, actualDataString, and isStrict.
The result messages are pretty clear, which is important when comparing really big JSON objects.
As a general architectural point, I usually advise against letting dependencies on a particular serialization format bleed out beyond your storage/networking layer; thus, I'd first recommend that you consider testing equality between your own application objects rather than their JSON manifestations.
Having said that, I'm currently a big fan of Jackson which my quick read of their ObjectNode.equals() implementation suggests does the set membership comparison that you want:
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;
}
I have change a bit in your solution to get the wanted result.
I would do my difference check in List, therefore I will create method to change JSON to list of strings based on your code:
private static List<String> jsonToList(String json){
List<String> list = new ArrayList<>();
Gson gson = new Gson();
Type type = new TypeToken<Map<String, Object>>(){}.getType();
Map<String, Object> jsonMap = gson.fromJson(json, type);
Map<String, Object> flatten = FlatMapUtil.flatten(jsonMap);
flatten.forEach((k, v) -> list.add(v.toString()));
return list;
}
Update
When I answered the question I did things a bit fast, the jsonToList was based on your code. As it is right now it is over complicated to what you are asking for. I have therefore made much lighter version using the following method in stead:
private static List<String> jsonToList(String json) {
JSONObject response = new JSONObject(json);
List<String> list = new ArrayList<>();
JSONArray jsonArray = response.getJSONArray("categories");
if (jsonArray != null) {
for (int i = 0; i < jsonArray.length(); i++) {
list.add(jsonArray.get(i).toString());
}
}
return list;
}
That said, now you have two choices and it is up to you to find out which one fits best to your needs and take it from here.
End of Update
for this example I have made 3 test examples
String main = "{\"categories\":[\"May\",\"Apr\",\"Mar\"]}";
String json1 = "{\"categories\":[\"May\",\"May\",\"Apr\",\"Apr\",\"Mar\",\"Mar\"]}";
String json2 = "{\"categories\":[\"May\",\"Apr\",\"Apr\",\"Mar\",\"Mar\",\"Mar\"]}";
String json3 = "{\"categories\":[\"May\",\"Apr\",\"Mar\",\"Mar\"]}";
in my second step I will create a
List<String> mainList = jsonToList(main);
List<String> list1 = jsonToList(json1);
so far so good. Now I make a method to take the extra difference of the 2 list, that mean as you requested in your comments, we take only all values that are duplicated more than once and return them in list. In this method I used hashmap only count duplicates and than take the all that is repeated more than 1 time:
private static List<String> diffList(List<String> mainList, List<String> secondList){
List<String> list = new ArrayList<String>();
Map<String, Integer> wordCount = new HashMap<>();
for(String word: secondList) {
if(mainList.contains(word)) {
Integer count = wordCount.get(word);
wordCount.put(word, (count == null) ? 1 : count + 1);
if(wordCount.get(word) > 1){
list.add(word);
}
}
}
return list;
}
Finally I would test all cases, for instance for list1:
List<String> diff1 = diffList(mainList, list1);
for (String s : diff1) {
System.out.println(s);
}
The output will be
May
Apr
Mar
for list2
Apr
Mar
Mar
And for list3
Mar
Now I will separate view method from the your method and create some thing like, just to make my code more clear and easy to work with:
private static String viewResult(List<String> list1, List<String> list2, List<String> duplicate){
String result;
StringBuilder SB = new StringBuilder("</br>");
SB.append("Entries only on LEFT: </br>");
list1.forEach(e -> SB.append(e + "</br>"));
SB.append("Entries only on RIGHT: </br>");
list2.forEach(e -> SB.append(e + "</br>"));
SB.append("Entries full difference : </br>");
duplicate.forEach(e -> SB.append(e + "</br>"));
result = SB.toString();
return result;
}
So if we put all this code together I will be some thing like this, and the following code is to demonstrate how things works, but from here you can take it to the next level in your code:
public static void main(String[] args) {
String main = "{\"categories\":[\"May\",\"Apr\",\"Mar\"]}";
String json1 = "{\"categories\":[\"May\",\"May\",\"Apr\",\"Apr\",\"Mar\",\"Mar\"]}";
String json2 = "{\"categories\":[\"May\",\"Apr\",\"Apr\",\"Mar\",\"Mar\",\"Mar\"]}";
String json3 = "{\"categories\":[\"May\",\"Apr\",\"Mar\",\"Mar\"]}";
List<String> mainList = jsonToList(main);
List<String> list1 = jsonToList(json1);
List<String> diff1 = diffList(mainList, list1);
for (String s : diff1) {
System.out.println(s);
}
String view = viewResult(mainList, list1, diff1);
}
private static List<String> jsonToList(String json){
List<String> list = new ArrayList<String>();
Gson gson = new Gson();
Type type = new TypeToken<Map<String, Object>>(){}.getType();
Map<String, Object> jsonMap = gson.fromJson(json, type);
Map<String, Object> flatten = FlatMapUtil.flatten(jsonMap);
flatten.forEach((k, v) -> list.add(v.toString()));
return list;
}
private static List<String> diffList(List<String> mainList, List<String> secondList){
List<String> list = new ArrayList<String>();
Map<String, Integer> wordCount = new HashMap<>();
for(String word: secondList) {
if(mainList.contains(word)) {
Integer count = wordCount.get(word);
wordCount.put(word, (count == null) ? 1 : count + 1);
if(wordCount.get(word) > 1){
list.add(word);
}
}
}
return list;
}
private static String viewResult(List<String> list1, List<String> list2, List<String> duplicate){
String result;
StringBuilder SB = new StringBuilder("</br>");
SB.append("Entries only on LEFT: </br>");
list1.forEach(e -> SB.append(e + "</br>"));
SB.append("Entries only on RIGHT: </br>");
list2.forEach(e -> SB.append(e + "</br>"));
SB.append("Entries full difference : </br>");
duplicate.forEach(e -> SB.append(e + "</br>"));
result = SB.toString();
return result;
}
If you want something more generic with a good diff you could utilize AssertJ here. Its usually used for Testing, but the diff looks really good and you can also use it in normal code.
Example:
Expecting:
<["Mai", "Apr", "Mar"]>
to contain exactly in any order:
<["May", "Apr", "Mar", "Mar"]>
elements not found:
<["May", "Mar"]>
and elements not expected:
<["Mai"]>
Can be created by:
[...]
import org.assertj.core.api.Assertions;
public class JsonTest {
final static String arr = " [\n"+
" \"Mai\",\n"+
" \"Apr\",\n"+
" \"Mar\"\n"+
" ]";
final static String arr2 = " [\n"+
" \"May\",\n"+
" \"Apr\",\n"+
" \"Mar\",\n"+
" \"Mar\"\n"+
" ]";
public static void main(String[] args){
System.out.println(smartJSONsCompare(arr,arr2));
}
private static String smartJSONsCompare(String leftJson, String rightJson) {
Gson gson = new Gson();
Type type = new TypeToken<List<String>>(){}.getType();
List<String> left = gson.fromJson(leftJson, type);
List<String> right = gson.fromJson(rightJson, type);
try{
Assertions.assertThat(left).containsExactlyInAnyOrderElementsOf(right);
}catch(AssertionError ae){
return ae.getMessage();
}
return "Matched";
}
}
I added the dependencies in gradle with:
dependencies {
compile("org.assertj:assertj-core:3.11.1")
}