
org.zalando.zjsonpatch.Applicator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of zjsonpatch Show documentation
Show all versions of zjsonpatch Show documentation
Java library to find / apply JSON patches
The newest version!
package org.zalando.zjsonpatch;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.NullNode;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import static org.zalando.zjsonpatch.Constants.FROM;
import static org.zalando.zjsonpatch.Constants.OP;
import static org.zalando.zjsonpatch.Constants.PATH;
import static org.zalando.zjsonpatch.Constants.VALUE;
import static org.zalando.zjsonpatch.FeatureFlags.MISSING_VALUES_AS_NULLS;
public final class Applicator {
/**
* Set of feature flags for patch application.
*/
private final Set flags;
public Applicator(Set flags) {
this.flags = flags;
}
private JsonNode resolve(JsonNode node, String attr) {
JsonNode child = node.get(attr);
if (child == null) {
throw new JsonPatchException("invalid patch (missing field: " + attr + ")");
}
return child;
}
private JsonNode resolve(JsonNode node, String attr, JsonNode defaultValue) {
JsonNode child = node.get(attr);
return (child == null) ? defaultValue : child;
}
private List path(JsonNode patch, String path) {
return PathHelper.getPath(resolve(patch, path).asText());
}
private JsonNode value(JsonNode node) {
if (!flags.contains(MISSING_VALUES_AS_NULLS)) {
return resolve(node, VALUE);
} else {
return resolve(node, VALUE, NullNode.getInstance());
}
}
private void patch(Processor processor, JsonNode patch) {
OpType operation = OpType.fromRfcName(resolve(patch, OP).asText());
switch (operation) {
case ADD: {
JsonNode value = value(patch);
processor.add(path(patch, PATH), value);
break;
}
case TEST: {
JsonNode value = value(patch);
processor.test(path(patch, PATH), value);
break;
}
case REPLACE: {
JsonNode value = value(patch);
processor.replace(path(patch, PATH), value);
break;
}
case REMOVE: {
processor.remove(path(patch, PATH));
break;
}
case MOVE: {
processor.move(path(patch, FROM), path(patch, PATH));
break;
}
case COPY: {
processor.copy(path(patch, FROM), path(patch, PATH));
break;
}
default:
throw new JsonPatchException("invalid patch (unsupported operation: " +
resolve(patch, OP).asText() + ")");
}
}
private List apply(Processor processor, Iterator patches) {
List excepts = new ArrayList();
for (int index = 0; patches.hasNext(); index++) {
try {
JsonNode patch = patches.next();
if (!patch.isObject()) {
throw new JsonPatchException("invalid patch (patch not an object - index: " + index + ")");
}
try {
patch(processor, patch);
} catch (JsonPatchException except) {
throw new JsonPatchException(message(except, patch, index), except);
}
} catch (JsonPatchException except) {
excepts.add(except);
}
}
return excepts;
}
public JsonNode apply(Processor processor, JsonNode patch) {
if (!patch.isArray()) {
throw new JsonPatchException("invalid patch (root not an array)");
}
rethrow(apply(processor, patch.iterator()));
return processor.result();
}
private String message(Exception except, JsonNode patch, int index) {
return "[" + resolve(patch, Constants.OP).asText() + "] "
+ except.getMessage() + "\n\t\t=> applying patch/" + index + ": " + patch;
}
private void rethrow(List excepts) {
switch (excepts.size()) {
case 0:
return;
case 1:
throw excepts.get(0);
default:
StringBuilder message = new StringBuilder("invalid patch");
for (Exception suppressed : excepts) {
message.append("\n\t").append(suppressed.getMessage());
}
JsonPatchException except = new JsonPatchException(message.toString());
/* Java 1.7 extension for (Exception suppressed : excepts) { except.addSuppressed(suppressed); } */
throw except;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy