Google gson の JsonParserを使用して 2つのJSONの差をラムダで処理するもの。
import java.io.Reader; import java.io.StringReader; import java.util.HashMap; import java.util.Map; import java.util.function.BiConsumer; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonParser; import com.google.gson.JsonPrimitive; /** * 2つのJSON比較、key の path 表現は "."区切り、配列は [Index]で表現 * 例) aaa.bbb[2].c → 30 * { aaa: { bbb:[ { a:1, b:2, c:3 },{ a:11, b:12, c:13 },{ a:10, b:20, c:30 } ] } } */ public final class JSonDiff{ private BiConsumer<String, Object> leftOnly; private BiConsumer<String, Object> rightOnly; private BiConsumer<String, Object> same; private BiConsumer<String, Object[]> both; private Map<String, Object> leftMap; private Map<String, Object> rightMap; /* 値だけに差がある BiConsumer で キーと値配列指定、[0]=左側JSONの値、[1]=右側JSONの値*/ public JSonDiff(BiConsumer<String, Object[]> both){ this.both = both; } /* 左側JSONしか存在しないBiConsumer で キーと値 */ public JSonDiff addLeft(BiConsumer<String, Object> leftOnly){ this.leftOnly = leftOnly; return this; } /* 右側JSONしか存在しないBiConsumer で キーと値 */ public JSonDiff addRight(BiConsumer<String, Object> rightOnly){ this.rightOnly = rightOnly; return this; } /* 差がないBiConsumer で キーと値 */ public JSonDiff addSame(BiConsumer<String, Object> same){ this.same = same; return this; } /* 差分の検査実行 */ public void scan(String left, String right){ scan(new StringReader(left), new StringReader(right)); } public void scan(Reader left, Reader right){ leftMap = new HashMap<>(); rightMap = new HashMap<>(); JsonElement jeLeft = new JsonParser().parse(left); if (jeLeft.isJsonObject()){ jeLeft.getAsJsonObject().entrySet() .forEach(entry->leftMap.putAll(maped(entry.getKey(), entry.getValue(), leftMap))); } JsonElement jeRight = new JsonParser().parse(right); if (jeRight.isJsonObject()){ jeRight.getAsJsonObject().entrySet() .forEach(entry->rightMap.putAll(maped(entry.getKey(), entry.getValue(), rightMap))); } leftMap.entrySet().forEach(le->{ if (rightMap.containsKey(le.getKey())){ Object l = le.getValue(); Object r = rightMap.get(le.getKey()); if (l==null){ if (r==null){ if (same != null) same.accept(le.getKey(), null); }else{ both.accept(le.getKey(), new Object[]{ l, r }); } }else{ if (r==null){ both.accept(le.getKey(), new Object[]{ l, r }); }else{ if (l.equals(r)){ if (same != null) same.accept(le.getKey(), l); }else{ both.accept(le.getKey(), new Object[]{ l, r }); } } } }else{ if (leftOnly != null) leftOnly.accept(le.getKey(), le.getValue()); } }); rightMap.entrySet().forEach(re->{ if (!leftMap.containsKey(re.getKey())){ if (rightOnly != null) rightOnly.accept(re.getKey(), re.getValue()); } }); } private Map<String, Object> maped(String key, JsonElement je, Map<String, Object> map){ if (je.isJsonNull()){ map.put(key, null); }else if(je.isJsonObject()){ je.getAsJsonObject().entrySet() .forEach(entry->map.putAll(maped(key + "." + entry.getKey(), entry.getValue(), map))); }else if(je.isJsonArray()){ JsonArray jary = je.getAsJsonArray(); int i = 0; for(JsonElement e:jary){ maped(key + "[" + i + "]", e, map); i++; } }else if(je.isJsonPrimitive()){ JsonPrimitive p = je.getAsJsonPrimitive(); if (p.isNumber()){ map.put(key, p.getAsDouble()); }else if(p.isString()){ map.put(key, p.getAsString()); }else if(p.isBoolean()){ map.put(key, p.getAsBoolean()); }else if(p.isJsonNull()){ map.put(key, null); } } return map; } }
使用例
try(Reader leftReader = new FileReader(new File("sample1.json")); Reader rightReader = new FileReader(new File("sample2.json"))){ JSonDiff diff = new JSonDiff((k, ary)->{ // 同一キー、差分、k = key , ary[0]:sample1.json の値、ary[1]:sample2.json の値 }); diff.addLeft((k, v)->{ // sample1.json だけに存在、k = key , v = 値 }); diff.addRight((k, v)->{ // sample2.json だけに存在、k = key , v = 値 }); diff.addSame((k, v)->{ // 両方同じキーと値である、k = key , v = 値 }); diff.scan(leftReader, rightReader); }catch(Exception e){ e.printStackTrace(); }