
com.github.fge.jsonpatch.JsonPatch Maven / Gradle / Ivy
Show all versions of json-patch Show documentation
/*
* Copyright (c) 2013, Francis Galiegue
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Lesser GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Lesser GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
package com.github.fge.jsonpatch;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.databind.JsonNode;
import com.github.fge.jackson.JacksonUtils;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.util.List;
import static com.github.fge.jsonpatch.JsonPatchMessages.*;
/**
* Implementation of JSON Patch
*
* JSON
* Patch, as its name implies, is an IETF draft describing a mechanism to
* apply a patch to any JSON value. This implementation covers all operations
* according to the specification; however, there are some subtle differences
* with regards to some operations which are covered in these operations'
* respective documentation.
*
* An example of a JSON Patch is as follows:
*
*
* [
* {
* "op": "add",
* "path": "/-",
* "value": {
* "productId": 19,
* "name": "Duvel",
* "type": "beer"
* }
* }
* ]
*
*
* This patch contains a single operation which adds an item at the end of
* an array. A JSON Patch can contain more than one operation; in this case, all
* operations are applied to the input JSON value in their order of appearance,
* until all operations are applied or an error condition is encountered.
*
* The main point where this implementation differs from the specification
* is initial JSON parsing. The draft says:
*
*
* Operation objects MUST have exactly one "op" member
*
*
* and:
*
*
* Additionally, operation objects MUST have exactly one "path" member.
*
*
* However, obeying these to the letter forces constraints on the JSON
* parser. Here, these constraints are not enforced, which means:
*
*
* [ { "op": "add", "op": "remove", "path": "/x" } ]
*
*
* is parsed (as a {@code remove} operation, since it appears last).
*
* IMPORTANT NOTE: the JSON Patch is supposed to be VALID when the
* constructor for this class ({@link JsonPatch#fromJson(JsonNode)} is used.
*/
public final class JsonPatch
{
/**
* List of operations
*/
private final List operations;
/**
* Package-visible constructor
*
* Visible only for testing purposes. Also used for deserialization.
*
* @param operations the list of operations for this patch
* @see JsonPatchOperation
*/
@JsonCreator
@VisibleForTesting
JsonPatch(final List operations)
{
this.operations = ImmutableList.copyOf(operations);
}
/**
* Static factory method to build a JSON Patch out of a JSON representation
*
* @param node the JSON representation of the generated JSON Patch
* @return a JSON Patch
* @throws IOException input is not a valid JSON patch
* @throws NullPointerException input is null
*/
public static JsonPatch fromJson(final JsonNode node)
throws IOException
{
Preconditions.checkNotNull(node, NULL_INPUT);
return JacksonUtils.getReader().withType(JsonPatch.class)
.readValue(node);
}
/**
* Apply this patch to a JSON value
*
* @param node the value to apply the patch to
* @return the patched JSON value
* @throws JsonPatchException failed to apply patch
* @throws NullPointerException input is null
*/
public JsonNode apply(final JsonNode node)
throws JsonPatchException
{
Preconditions.checkNotNull(node, NULL_INPUT);
JsonNode ret = node;
for (final JsonPatchOperation operation: operations)
ret = operation.apply(ret);
return ret;
}
@Override
public String toString()
{
return operations.toString();
}
}