Package ca.marcusdunn.jsonlens.patch
@NullMarked
package ca.marcusdunn.jsonlens.patch
RFC 6902 JSON Patch: JsonPatch, its operations (Operation), and its errors (PatchError).
// Keep numbers exact, and reject duplicate names, so that a patch with two "op" members fails.
JsonMapper mapper = JsonMapper.builder()
.enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS)
.enable(StreamReadFeature.STRICT_DUPLICATE_DETECTION)
.build();
JsonNode document = mapper.readTree("""
{"baz": "qux", "foo": "bar"}""");
JsonNode patchDocument = mapper.readTree("""
[{"op": "replace", "path": "/baz", "value": "boo"},
{"op": "add", "path": "/hello", "value": ["world"]},
{"op": "remove", "path": "/foo"}]""");
// Read the patch with any model, and apply it in place with an editable model.
Result<JsonNode, PatchError> result = JsonPatch.parse(patchDocument, JacksonJsonModel.INSTANCE)
.flatMap(patch -> patch.apply(document, JacksonJsonModel.INSTANCE));
switch (result) {
case Result.Ok<JsonNode, PatchError>(JsonNode root) -> lines.add("patched: " + root);
case Result.Err<JsonNode, PatchError>(PatchError error) -> lines.add(error.message());
}
// patched: {"baz":"boo","hello":["world"]}
// A patch is atomic: after an error, the document has its original value.
JsonNode failing = mapper.readTree("""
[{"op": "replace", "path": "/baz", "value": 42},
{"op": "test", "path": "/baz", "value": "C"}]""");
Result<JsonNode, PatchError> failed = JsonPatch.parse(failing, JacksonJsonModel.INSTANCE)
.flatMap(patch -> patch.apply(document, JacksonJsonModel.INSTANCE));
// failed: Err[error=TestFailed[operation=1]], document: {"baz":"boo","hello":["world"]}
-
ClassDescriptionJsonPatch<P>A JSON Patch (RFC 6902): a sequence of operations that changes a JSON document.Operation<P>An operation of a JSON Patch (RFC 6902, Section 4).
add(Section 4.1): adds a member, inserts an array element, or replaces the whole document.copy(Section 4.5): adds a copy of the value atfromat the target location.move(Section 4.4): removes the value atfromand adds it at the target location.remove(Section 4.2): removes the value at the target location.replace(Section 4.3): replaces the value at the target location.test(Section 4.6): tests that the value at the target location is equal to a value.An error of a JSON Patch: a patch document that violates RFC 6902, or an operation that is not successful (RFC 6902, Section 5).An operation has a member more than once.Thefromlocation of amoveor acopydoes not exist (Sections 4.4 and 4.5).Thepathorfrommember of an operation is not a valid JSON Pointer.An operation has no member that it needs:opandpath(Section 4),valueforadd,replace, andtest, orfromformoveandcopy.Thefromlocation of amoveis a proper prefix of itspath(Section 4.4).The patch document is not an array (RFC 6902, Section 3).An operation is not an object (RFC 6902, Section 3).Theop,path, orfrommember of an operation is not a string.The target location does not exist.Aremovehas the whole document as its target.The value at the target location of atestis not equal to its value (Section 4.6).Theopof an operation is not one of the six operations (Section 4).The value of an operation cannot be added to the target document: the target model cannot hold one of its numbers, for example1e99999999999in a Jackson tree, or an object of the value has duplicate member names, which have no defined value (RFC 8259, Section 4).