com.azure.core.models.JsonPatchDocument Maven / Gradle / Ivy
Show all versions of azure-core Show documentation
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
package com.azure.core.models;
import com.azure.core.implementation.Option;
import com.azure.core.util.serializer.JacksonAdapter;
import com.azure.core.util.serializer.JsonSerializer;
import com.azure.core.util.serializer.JsonSerializerProviders;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonValue;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* Represents a JSON Patch document.
*/
public final class JsonPatchDocument {
private static final Object SERIALIZER_INSTANTIATION_SYNCHRONIZER = new Object();
private static volatile JsonSerializer defaultSerializer;
@JsonIgnore
private final JsonSerializer serializer;
@JsonValue
private final List operations;
/**
* Creates a new JSON Patch document.
*/
public JsonPatchDocument() {
this(null);
}
/**
* Creates a new JSON Patch document.
*
* If {@code serializer} isn't specified {@link JacksonAdapter} will be used.
*
* @param serializer The {@link JsonSerializer} that will be used to serialize patch operation values.
*/
public JsonPatchDocument(JsonSerializer serializer) {
this.operations = new ArrayList<>();
this.serializer = serializer;
}
/**
* Gets a representation of the {@link JsonPatchOperation JSON patch operations} in this JSON patch document.
*
* Modifications to the returned list won't mutate the operations in the document.
*
* @return The JSON patch operations in this JSON patch document.
*/
List getOperations() {
return new ArrayList<>(operations);
}
/**
* Appends an "add" operation to this JSON Patch document.
*
* If the {@code path} doesn't exist a new member is added to the object. If the {@code path} does exist the
* previous value is replaced. If the {@code path} specifies an array index the value is inserted at the specified.
*
* See JSON Patch Add for more information.
*
*
Code Samples
*
*
*
* /*
* * Add an object member to the JSON document { "foo" : "bar" } to get the JSON document
* * { "bar": "foo", "foo": "bar" }.
* */
* jsonPatchDocument.appendAdd("/bar", "foo");
*
* /*
* * Add an array element to the JSON document { "foo": [ "fizz", "fizzbuzz" ] } to get the JSON document
* * { "foo": [ "fizz", "buzz", "fizzbuzz" ] }.
* */
* jsonPatchDocument.appendAdd("/foo/1", "buzz");
*
* /*
* * Add a nested member to the JSON document { "foo": "bar" } to get the JSON document
* * { "foo": "bar", "child": { "grandchild": { } } }.
* */
* jsonPatchDocument.appendAdd("/child", Collections.singletonMap("grandchild", Collections.emptyMap()));
*
* /*
* * Add an array element to the JSON document { "foo": [ "fizz", "buzz" ] } to get the JSON document
* * { "foo": [ "fizz", "buzz", "fizzbuzz" ] }.
* */
* jsonPatchDocument.appendAdd("/foo/-", "fizzbuzz");
*
*
*
* @param path The path to apply the addition.
* @param value The value that will be serialized and added to the path.
* @return The updated JsonPatchDocument object.
* @throws NullPointerException If {@code path} is null.
*/
public JsonPatchDocument appendAdd(String path, Object value) {
return appendAddInternal(path, serializeValue(value));
}
/**
* Appends an "add" operation to this JSON Patch document.
*
* If the {@code path} doesn't exist a new member is added to the object. If the {@code path} does exist the
* previous value is replaced. If the {@code path} specifies an array index the value is inserted at the specified.
*
* See JSON Patch Add for more information.
*
*
Code Samples
*
*
*
* /*
* * Add an object member to the JSON document { "foo" : "bar" } to get the JSON document
* * { "bar": "foo", "foo": "bar" }.
* */
* jsonPatchDocument.appendAddRaw("/bar", "\"foo\"");
*
* /*
* * Add an array element to the JSON document { "foo": [ "fizz", "fizzbuzz" ] } to get the JSON document
* * { "foo": [ "fizz", "buzz", "fizzbuzz" ] }.
* */
* jsonPatchDocument.appendAddRaw("/foo/1", "\"buzz\"");
*
* /*
* * Add a nested member to the JSON document { "foo": "bar" } to get the JSON document
* * { "foo": "bar", "child": { "grandchild": { } } }.
* */
* jsonPatchDocument.appendAddRaw("/child", "\"child\": { \"grandchild\": { } }");
*
* /*
* * Add an array element to the JSON document { "foo": [ "fizz", "buzz" ] } to get the JSON document
* * { "foo": [ "fizz", "buzz", "fizzbuzz" ] }.
* */
* jsonPatchDocument.appendAddRaw("/foo/-", "\"fizzbuzz\"");
*
*
*
* @param path The path to apply the addition.
* @param rawJson The raw JSON value that will be added to the path.
* @return The updated JsonPatchDocument object.
* @throws NullPointerException If {@code path} is null.
*/
public JsonPatchDocument appendAddRaw(String path, String rawJson) {
return appendAddInternal(path, Option.of(rawJson));
}
private JsonPatchDocument appendAddInternal(String path, Option rawJsonOption) {
Objects.requireNonNull(path, "'path' cannot be null.");
return appendOperation(JsonPatchOperationKind.ADD, null, path, rawJsonOption);
}
/**
* Appends a "replace" operation to this JSON Patch document.
*
* See JSON Patch replace for more information.
*
*
Code Samples
*
*
*
* /*
* * Replace an object member in the JSON document { "bar": "qux", "foo": "bar" } to get the JSON document
* * { "bar": "foo", "foo": "bar" }.
* */
* jsonPatchDocument.appendReplace("/bar", "foo");
*
* /*
* * Replace an object member in the JSON document { "foo": "fizz" } to get the JSON document
* * { "foo": [ "fizz", "buzz", "fizzbuzz" ] }.
* */
* jsonPatchDocument.appendReplace("/foo", new String[] {"fizz", "buzz", "fizzbuzz"});
*
* /*
* * Given the JSON document { "foo": "bar" } the following is an example of an invalid replace operation as the
* * target path doesn't exist in the document.
* */
* jsonPatchDocument.appendReplace("/baz", "foo");
*
*
*
* @param path The path to replace.
* @param value The value will be serialized and used as the replacement.
* @return The updated JsonPatchDocument object.
* @throws NullPointerException If {@code path} is null.
*/
public JsonPatchDocument appendReplace(String path, Object value) {
return appendReplaceInternal(path, serializeValue(value));
}
/**
* Appends a "replace" operation to this JSON Patch document.
*
* See JSON Patch replace for more information.
*
*
Code Samples
*
*
*
* /*
* * Replace an object member in the JSON document { "bar": "qux", "foo": "bar" } to get the JSON document
* * { "bar": "foo", "foo": "bar" }.
* */
* jsonPatchDocument.appendReplaceRaw("/bar", "\"foo\"");
*
* /*
* * Replace an object member in the JSON document { "foo": "fizz" } to get the JSON document
* * { "foo": [ "fizz", "buzz", "fizzbuzz" ] }.
* */
* jsonPatchDocument.appendReplaceRaw("/foo", "[ \"fizz\", \"buzz\", \"fizzbuzz\" ]");
*
* /*
* * Given the JSON document { "foo": "bar" } the following is an example of an invalid replace operation as the
* * target path doesn't exist in the document.
* */
* jsonPatchDocument.appendReplaceRaw("/baz", "\"foo\"");
*
*
*
* @param path The path to replace.
* @param rawJson The raw JSON value that will be used as the replacement.
* @return The updated JsonPatchDocument object.
* @throws NullPointerException If {@code path} is null.
*/
public JsonPatchDocument appendReplaceRaw(String path, String rawJson) {
return appendReplaceInternal(path, Option.of(rawJson));
}
private JsonPatchDocument appendReplaceInternal(String path, Option rawJsonOption) {
Objects.requireNonNull(path, "'path' cannot be null.");
return appendOperation(JsonPatchOperationKind.REPLACE, null, path, rawJsonOption);
}
/**
* Appends a "copy" operation to this JSON Patch document.
*
* See JSON Patch copy for more information.
*
*
Code Samples
*
*
*
* /*
* * Copy an object member in the JSON document { "foo": "bar" } to get the JSON document
* * { "foo": "bar", "copy": "bar" }.
* */
* jsonPatchDocument.appendCopy("/foo", "/copy");
*
* /*
* * Copy an object member in the JSON document { "foo": { "bar": "baz" } } to get the JSON document
* * { "foo": { "bar": "baz" }, "bar": "baz" }.
* */
* jsonPatchDocument.appendCopy("/foo/bar", "/bar");
*
* /*
* * Given the JSON document { "foo": "bar" } the following is an example of an invalid copy operation as the
* * target from doesn't exist in the document.
* */
* jsonPatchDocument.appendCopy("/baz", "/fizz");
*
*
*
* @param from The path to copy from.
* @param path The path to copy to.
* @return The updated JsonPatchDocument object.
* @throws NullPointerException If {@code from} or {@code path} is null.
*/
public JsonPatchDocument appendCopy(String from, String path) {
Objects.requireNonNull(from, "'from' cannot be null.");
Objects.requireNonNull(path, "'path' cannot be null.");
return appendOperation(JsonPatchOperationKind.COPY, from, path, Option.uninitialized());
}
/**
* Appends a "move" operation to this JSON Patch document.
*
* For the operation to be successful {@code path} cannot be a child node of {@code from}.
*
* See JSON Patch move for more information.
*
*
Code Samples
*
*
*
* /*
* * Move an object member in the JSON document { "foo": "bar", "bar": "foo" } to get the JSON document
* * { "bar": "bar" }.
* */
* jsonPatchDocument.appendMove("/foo", "/bar");
*
* /*
* * Move an object member in the JSON document { "foo": { "bar": "baz" } } to get the JSON document
* * { "foo": "baz" }.
* */
* jsonPatchDocument.appendMove("/foo/bar", "/foo");
*
* /*
* * Given the JSON document { "foo": { "bar": "baz" } } the following is an example of an invalid move operation
* * as the target path is a child of the target from.
* */
* jsonPatchDocument.appendMove("/foo", "/foo/bar");
*
* /*
* * Given the JSON document { "foo": "bar" } the following is an example of an invalid move operation as the
* * target from doesn't exist in the document.
* */
* jsonPatchDocument.appendMove("/baz", "/fizz");
*
*
*
* @param from The path to move from.
* @param path The path to move to.
* @return The updated JsonPatchDocument object.
* @throws NullPointerException If {@code from} or {@code path} is null.
*/
public JsonPatchDocument appendMove(String from, String path) {
Objects.requireNonNull(from, "'from' cannot be null.");
Objects.requireNonNull(path, "'path' cannot be null.");
return appendOperation(JsonPatchOperationKind.MOVE, from, path, Option.uninitialized());
}
/**
* Appends a "remove" operation to this JSON Patch document.
*
* See JSON Patch remove for more information.
*
*
Code Samples
*
*
*
* /*
* * Remove an object member in the JSON document { "foo": "bar", "bar": "foo" } to get the JSON document
* * { "foo": "bar" }.
* */
* jsonPatchDocument.appendRemove("/bar");
*
* /*
* * Remove an object member in the JSON document { "foo": { "bar": "baz" } } to get the JSON document
* * { "foo": { } }.
* */
* jsonPatchDocument.appendRemove("/foo/bar");
*
* /*
* * Given the JSON document { "foo": "bar" } the following is an example of an invalid remove operation as the
* * target from doesn't exist in the document.
* */
* jsonPatchDocument.appendRemove("/baz");
*
*
*
* @param path The path to remove.
* @return The updated JsonPatchDocument object.
* @throws NullPointerException If {@code path} is null.
*/
public JsonPatchDocument appendRemove(String path) {
Objects.requireNonNull(path, "'path' cannot be null.");
return appendOperation(JsonPatchOperationKind.REMOVE, null, path, Option.uninitialized());
}
/**
* Appends a "test" operation to this JSON Patch document.
*
* See JSON Patch test for more information.
*
*
Code Samples
*
*
*
* /*
* * Test an object member in the JSON document { "foo": "bar" } to get a successful operation.
* */
* jsonPatchDocument.appendTest("/foo", "bar");
*
* /*
* * Test an object member in the JSON document { "foo": "bar" } to get a unsuccessful operation.
* */
* jsonPatchDocument.appendTest("/foo", 42);
*
* /*
* * Given the JSON document { "foo": "bar" } the following is an example of an unsuccessful test operation as
* * the target path doesn't exist in the document.
* */
* jsonPatchDocument.appendTest("/baz", "bar");
*
*
*
* @param path The path to test.
* @param value The value that will be serialized and used to test against.
* @return The updated JsonPatchDocument object.
* @throws NullPointerException If {@code path} is null.
*/
public JsonPatchDocument appendTest(String path, Object value) {
return appendTestInternal(path, serializeValue(value));
}
/**
* Appends a "test" operation to this JSON Patch document.
*
* See JSON Patch test for more information.
*
*
Code Samples
*
*
*
* /*
* * Test an object member in the JSON document { "foo": "bar" } to get a successful operation.
* */
* jsonPatchDocument.appendTestRaw("/foo", "\"bar\"");
*
* /*
* * Test an object member in the JSON document { "foo": "bar" } to get a unsuccessful operation.
* */
* jsonPatchDocument.appendTestRaw("/foo", "42");
*
* /*
* * Given the JSON document { "foo": "bar" } the following is an example of an unsuccessful test operation as
* * the target path doesn't exist in the document.
* */
* jsonPatchDocument.appendTestRaw("/baz", "\"bar\"");
*
*
*
* @param path The path to test.
* @param rawJson The raw JSON value that will be used to test against.
* @return The updated JsonPatchDocument object.
* @throws NullPointerException If {@code path} is null.
*/
public JsonPatchDocument appendTestRaw(String path, String rawJson) {
return appendTestInternal(path, Option.of(rawJson));
}
private JsonPatchDocument appendTestInternal(String path, Option rawJsonOption) {
Objects.requireNonNull(path, "'path' cannot be null.");
return appendOperation(JsonPatchOperationKind.TEST, null, path, rawJsonOption);
}
private Option serializeValue(Object value) {
if (value == null) {
return Option.empty();
}
byte[] bytes;
if (serializer == null) {
if (defaultSerializer == null) {
synchronized (SERIALIZER_INSTANTIATION_SYNCHRONIZER) {
if (defaultSerializer == null) {
defaultSerializer = JsonSerializerProviders.createInstance();
}
}
}
bytes = defaultSerializer.serializeToBytes(value);
} else {
bytes = serializer.serializeToBytes(value);
}
return Option.of(new String(bytes, StandardCharsets.UTF_8));
}
private JsonPatchDocument appendOperation(JsonPatchOperationKind operationKind, String from, String path,
Option optionalValue) {
operations.add(new JsonPatchOperation(operationKind, from, path, optionalValue));
return this;
}
/**
* Gets a formatted JSON string representation of this JSON Patch document.
*
* @return The formatted JSON String representing this JSON Patch document.
*/
@Override
public String toString() {
StringBuilder builder = new StringBuilder("[");
for (int i = 0; i < operations.size(); i++) {
if (i > 0) {
builder.append(",");
}
operations.get(i).buildString(builder);
}
return builder.append("]").toString();
}
}