JAVAで2つのJSONのDiffを取る

JSON同士の比較をするのに便利なものが無いかと調べたら *json-patch* なる物が見つかったので、どんなものかと試してみました。


## ライブラリ

https://github.com/fge/json-patch

やっていることは RFC6902 に規定してある内容のようで、
本来は Diff というより JSONに対してパッチを当てるような事をするのが目的っぽい。
その機能の１つに Diff があるといった所かな。。。（この辺は独り言なので真に受けないで）

*RFC6902*
http://www.hcn.zaq.ne.jp/___/WEB/RFC6902-ja.html


### テストコード

```java:JsonPatchCheck.java

public class JsonPatchCheck {

    private static final ObjectMapper mapper = new ObjectMapper();
    static {
        mapper.enable(SerializationFeature.INDENT_OUTPUT);
    }

    @Test(dataProvider = "data")
    public void test(String name, String description, JsonNode json1, JsonNode json2) throws Throwable {
        JsonNode diff = JsonDiff.asJson(json1, json2);
        print(name, description, json1, json2, diff);
    }

    @DataProvider(name = "data")
    public Object[][] data() throws Throwable {
        return new Object[][] {
                {
                    "Same",
                    "同じ内容JSONの比較",
                    mapper.readTree("{\"a\":\"0\" }"),
                    mapper.readTree("{\"a\":\"0\" }")
                },

                {
                    "Add",
                    "json1 に対し、 json2 に /a/c がある",
                    mapper.readTree("{\"a\": [{\"b\":\"1\"}]}"),
                    mapper.readTree("{\"a\": [{\"b\":\"1\"},{\"c\":\"2\"}]}")
                },

                {
                    "Remove",
                    "json1 に対し、 json2 に /a/c がない",
                    mapper.readTree("{\"a\": [{\"b\":\"1\"},{\"c\":\"2\"}]}"),
                    mapper.readTree("{\"a\": [{\"b\":\"1\"}]}")
                },

                {
                    "Replace",
                    "json1 と json2 とで /b の値が異なる",
                    mapper.readTree("{\"a\":\"0\",\"b\":\"1\"}"),
                    mapper.readTree("{\"a\":\"0\",\"b\":\"2\"}")
                },

                {
                    "Move",
                    "json1 の /b の値が、json2 の /c にある（/b から /c に移動している）",
                    mapper.readTree("{\"a\":\"0\",\"b\":\"1\"}"),
                    mapper.readTree("{\"a\":\"0\",\"c\":\"1\"}")
                },

                {
                    "Copy",
                    "json1 の /b の値が、json2 の /c に複製されている",
                    mapper.readTree("{\"a\":\"0\",\"b\":\"1\"}"),
                    mapper.readTree("{\"a\":\"0\",\"b\":\"1\",\"c\":\"1\"}")
                }
        };
    }

    public static void print(String name, String description, JsonNode json1, JsonNode json2, JsonNode diff) throws Throwable {
        System.out.println("■■■■■" + name + "■■■■■■");
        System.out.println("\n" + description + "\n");

        System.out.println("-------JSON1-------");
        System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(json1));

        System.out.println("-------JSON2-------");
        System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(json2));

        System.out.println("-------Diff-------");
        System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(diff));

        System.out.println("■■■■■■■■■■■■■■■");
    }

}

```

### 出力

```text:実行結果

■■■■■Same■■■■■■

同じ内容JSONの比較

-------JSON1-------
{
  "a" : "0"
}
-------JSON2-------
{
  "a" : "0"
}
-------Diff-------
[ ]
■■■■■■■■■■■■■■■
■■■■■Add■■■■■■

json1 に対し、 json2 に /a/c がある

-------JSON1-------
{
  "a" : [ {
    "b" : "1"
  } ]
}
-------JSON2-------
{
  "a" : [ {
    "b" : "1"
  }, {
    "c" : "2"
  } ]
}
-------Diff-------
[ {
  "op" : "add",
  "path" : "/a/-",
  "value" : {
    "c" : "2"
  }
} ]
■■■■■■■■■■■■■■■
■■■■■Remove■■■■■■

json1 に対し、 json2 に /a/c がない

-------JSON1-------
{
  "a" : [ {
    "b" : "1"
  }, {
    "c" : "2"
  } ]
}
-------JSON2-------
{
  "a" : [ {
    "b" : "1"
  } ]
}
-------Diff-------
[ {
  "op" : "remove",
  "path" : "/a/1"
} ]
■■■■■■■■■■■■■■■
■■■■■Replace■■■■■■

json1 と json2 とで /b の値が異なる

-------JSON1-------
{
  "a" : "0",
  "b" : "1"
}
-------JSON2-------
{
  "a" : "0",
  "b" : "2"
}
-------Diff-------
[ {
  "op" : "replace",
  "path" : "/b",
  "value" : "2"
} ]
■■■■■■■■■■■■■■■
■■■■■Move■■■■■■

json1 の /b の値が、json2 の /c にある（/b から /c に移動している）

-------JSON1-------
{
  "a" : "0",
  "b" : "1"
}
-------JSON2-------
{
  "a" : "0",
  "c" : "1"
}
-------Diff-------
[ {
  "op" : "move",
  "path" : "/c",
  "from" : "/b"
} ]
■■■■■■■■■■■■■■■
■■■■■Copy■■■■■■

json1 の /b の値が、json2 の /c に複製されている

-------JSON1-------
{
  "a" : "0",
  "b" : "1"
}
-------JSON2-------
{
  "a" : "0",
  "b" : "1",
  "c" : "1"
}
-------Diff-------
[ {
  "op" : "copy",
  "path" : "/c",
  "from" : "/b"
} ]
■■■■■■■■■■■■■■■

```

## 後書

出力された Diff をどう解析して、どう扱うかは目的に合わせて個々に考える必要がありそうですが、
Diff を取る分には問題なさそうです。