创建 JSON 补丁文档
除了other answer 中描述的方法之外,您还可以使用JSR 374 中定义的Java API for JSON Processing(它不适用于Gson 或Jackson)。需要以下依赖项:
<!-- Java API for JSON Processing (API) -->
<dependency>
<groupId>javax.json</groupId>
<artifactId>javax.json-api</artifactId>
<version>1.1.2</version>
</dependency>
<!-- Java API for JSON Processing (implementation) -->
<dependency>
<groupId>org.glassfish</groupId>
<artifactId>javax.json</artifactId>
<version>1.1.2</version>
</dependency>
然后您可以从 JSON 文档创建 JSON 差异。它将生成RFC 6902 中定义的 JSON Patch 文档:
JsonPatch diff = Json.createDiff(source, target);
当应用于源文档时,JSON 补丁会生成目标文档。 JSON Patch 可以通过以下方式应用于源文档:
JsonObject patched = diff.apply(source);
创建 JSON 合并补丁文档
根据您的需要,您可以创建一个在RFC 7396 中定义的 JSON 合并补丁文档:
JsonMergePatch mergeDiff = Json.createMergeDiff(source, target);
当应用于源文档时,JSON 合并补丁会生成目标文档。要修补源,请使用:
JsonValue patched = mergeDiff.apply(source);
漂亮的打印 JSON 文档
要漂亮地打印 JSON 文档,您可以使用:
System.out.println(format(diff.toJsonArray()));
System.out.println(format(mergeDiff.toJsonValue()));
public static String format(JsonValue json) {
StringWriter stringWriter = new StringWriter();
prettyPrint(json, stringWriter);
return stringWriter.toString();
}
public static void prettyPrint(JsonValue json, Writer writer) {
Map<String, Object> config =
Collections.singletonMap(JsonGenerator.PRETTY_PRINTING, true);
JsonWriterFactory writerFactory = Json.createWriterFactory(config);
try (JsonWriter jsonWriter = writerFactory.createWriter(writer)) {
jsonWriter.write(json);
}
}
示例
考虑以下 JSON 文档:
{
"name": {
"first": "John",
"last": "Doe"
},
"address": null,
"birthday": "1980-01-01",
"company": "Acme",
"occupation": "Software engineer",
"phones": [
{
"number": "000000000",
"type": "home"
},
{
"number": "999999999",
"type": "mobile"
}
]
}
{
"name": {
"first": "Jane",
"last": "Doe",
"nickname": "Jenny"
},
"birthday": "1990-01-01",
"occupation": null,
"phones": [
{
"number": "111111111",
"type": "mobile"
}
],
"favorite": true,
"groups": [
"close-friends",
"gym"
]
}
以下代码生成 JSON Patch:
JsonValue source = Json.createReader(new StringReader(leftJson)).readValue();
JsonValue target = Json.createReader(new StringReader(rightJson)).readValue();
JsonPatch diff = Json.createDiff(source.asJsonObject(), target.asJsonObject());
System.out.println(format(diff.toJsonArray()));
它将产生以下输出:
[
{
"op": "replace",
"path": "/name/first",
"value": "Jane"
},
{
"op": "add",
"path": "/name/nickname",
"value": "Jenny"
},
{
"op": "remove",
"path": "/address"
},
{
"op": "replace",
"path": "/birthday",
"value": "1990-01-01"
},
{
"op": "remove",
"path": "/company"
},
{
"op": "replace",
"path": "/occupation",
"value": null
},
{
"op": "replace",
"path": "/phones/1/number",
"value": "111111111"
},
{
"op": "remove",
"path": "/phones/0"
},
{
"op": "add",
"path": "/favorite",
"value": true
},
{
"op": "add",
"path": "/groups",
"value": [
"close-friends",
"gym"
]
}
]
现在考虑以下代码来生成 JSON 合并补丁:
JsonValue source = Json.createReader(new StringReader(leftJson)).readValue();
JsonValue target = Json.createReader(new StringReader(rightJson)).readValue();
JsonMergePatch mergeDiff = Json.createMergeDiff(source, target);
System.out.println(format(mergeDiff.toJsonValue()));
它将产生以下输出:
{
"name": {
"first": "Jane",
"nickname": "Jenny"
},
"address": null,
"birthday": "1990-01-01",
"company": null,
"occupation": null,
"phones": [
{
"number": "111111111",
"type": "mobile"
}
],
"favorite": true,
"groups": [
"close-friends",
"gym"
]
}
应用补丁时的不同结果
应用补丁文档时,上述方法的结果略有不同。考虑以下将 JSON Patch 应用于文档的代码:
JsonPatch diff = ...
JsonValue patched = diff.apply(source.asJsonObject());
System.out.println(format(patched));
它产生:
{
"name": {
"first": "Jane",
"last": "Doe",
"nickname": "Jenny"
},
"birthday": "1990-01-01",
"occupation": null,
"phones": [
{
"number": "111111111",
"type": "mobile"
}
],
"favorite": true,
"groups": [
"close-friends",
"gym"
]
}
现在考虑以下将 JSON Merge Patch 应用于文档的代码:
JsonMergePatch mergeDiff = ...
JsonValue patched = mergeDiff.apply(source);
System.out.println(format(patched));
它产生:
{
"name": {
"first": "Jane",
"last": "Doe",
"nickname": "Jenny"
},
"birthday": "1990-01-01",
"phones": [
{
"number": "111111111",
"type": "mobile"
}
],
"favorite": true,
"groups": [
"close-friends",
"gym"
]
}
在第一个示例中,occupation 属性为null。在第二个例子中,它被省略了。这是由于 JSON Merge Patch 上的 null 语义。来自RFC 7396:
如果目标确实包含该成员,则替换该值。合并补丁中的空值具有特殊含义,以指示删除目标中的现有值。 [...]
这种设计意味着合并补丁文档适用于描述对主要使用对象作为其结构并且不使用显式空值的 JSON 文档的修改。合并补丁格式不适用于所有 JSON 语法。