/* EXPERIMENTAL (really) */ /* Copyright (c) 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.senseidb.test.bql.parsers; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.lang.Math; import java.util.Iterator; /** * A comparator for comparing json objects. This comparator takes care of * reordered elements in JSONArray. {@link #STRICT} mode means the two given * elements must match exactly, while in {@link #SIMPLE} mode extra elements in * the latter is ignored. * * Check unittests {@link JsonComparatorTest} for examples on this. * * @author Sachin Shenoy */ public class JsonComparator { public static final int STRICT = 1; public static final int SIMPLE = 2; private final int policy; public JsonComparator(int policy) { this.policy = policy; } /** * Compares two json objects. * * @param a first element to compare * @param b second element to compare * @return true if the elements are equal as per the policy. */ public boolean isEquals(Object a, Object b) { if (a instanceof JSONObject) { if (b instanceof JSONObject) { return isEqualsJsonObject((JSONObject) a, (JSONObject) b); } else { return false; } } if (a instanceof JSONArray) { if (b instanceof JSONArray) { return isEqualsJsonArray((JSONArray) a, (JSONArray) b); } else { return false; } } if (a instanceof Long) { if (b instanceof Long) { return isEqualsLong((Long) a, (Long) b); } else if (b instanceof Integer) { return isEqualsLong((Long) a, new Long((long) ((Integer) b).intValue())); } else { return false; } } if (a instanceof Integer) { if (b instanceof Integer) { return isEqualsInteger((Integer) a, (Integer) b); } else if (b instanceof Long) { return isEqualsInteger((Integer) a, new Integer((int) ((Long) b).longValue())); } else { return false; } } if (a instanceof String) { if (b instanceof String) { return isEqualsString((String) a, (String) b); } else { return false; } } if (a instanceof Boolean) { if (b instanceof Boolean) { return isEqualsBoolean((Boolean) a, (Boolean) b); } else { return false; } } if (a instanceof Float || a instanceof Double) { double val1 = (a instanceof Float)? ((Float) a).doubleValue() : ((Double) a).doubleValue(); if (b instanceof Float || b instanceof Double) { double val2 = (b instanceof Float)? ((Float) b).doubleValue() : ((Double) b).doubleValue(); return (Math.abs(val1-val2) < 0.001); } else { return false; } } if (a == null && b == null){ return true; } if (a != null && b != null) { return a.equals(b); } return false; } private boolean isEqualsBoolean(Boolean a, Boolean b) { if (a == null ^ b == null) { return false; } else if (a == null && b == null) { return true; } return a.equals(b); } private boolean isEqualsString(String a, String b) { if (a == null ^ b == null) { return false; } else if (a == null && b == null) { return true; } return a.equals(b); } private boolean isEqualsLong(Long a, Long b) { if (a == null ^ b == null) { return false; } else if (a == null && b == null) { return true; } return a.equals(b); } private boolean isEqualsInteger(Integer a, Integer b) { if (a == null ^ b == null) { return false; } else if (a == null && b == null) { return true; } return a.equals(b); } private boolean isEqualsJsonArray(JSONArray a, JSONArray b) { if (policy == STRICT) { if (a.length() != b.length()) { return false; } } if (policy == SIMPLE) { if (a.length() > b.length()) { return false; } } boolean[] am = new boolean[a.length()]; boolean[] bm = new boolean[b.length()]; for (int i = 0; i < a.length(); ++i) if (am[i] == false) { for (int j = 0; j < b.length(); ++j) if (bm[j] == false) { try { if (isEquals(a.get(i), b.get(j))) { am[i] = true; bm[j] = true; break; } } catch (JSONException e) { e.printStackTrace(); } } } for (int i = 0; i < am.length; ++i) if (!am[i]) { return false; } if (policy == STRICT) { for (int j = 0; j < bm.length; ++j) if (!bm[j]) { return false; } } return true; } private boolean isEqualsJsonObject(JSONObject a, JSONObject b) { if (policy == STRICT) { if (a.length() != b.length()) { return false; } } if (policy == SIMPLE) { if (a.length() > b.length()) { return false; } } Iterator keys = a.keys(); while (keys.hasNext()) { String key = (String) keys.next(); if (!b.has(key)) { return false; } try { if (!isEquals(a.get(key), b.get(key))) { return false; } } catch (JSONException e) { return false; } } return true; } }