com.flipkart.zjsonpatch.JsonPatch.java Source code

Java tutorial

Introduction

Here is the source code for com.flipkart.zjsonpatch.JsonPatch.java

Source

/*
 * Copyright 2016 flipkart.com zjsonpatch.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/

package com.flipkart.zjsonpatch;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.NullNode;
import com.google.common.base.Function;
import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;

import java.util.EnumSet;
import java.util.Iterator;
import java.util.List;

/**
 * User: gopi.vishwakarma
 * Date: 31/07/14
 */
public final class JsonPatch {

    private static final DecodePathFunction DECODE_PATH_FUNCTION = new DecodePathFunction();

    private JsonPatch() {
    }

    private final static class DecodePathFunction implements Function<String, String> {
        @Override
        public String apply(String path) {
            return path.replaceAll("~1", "/").replaceAll("~0", "~"); // see http://tools.ietf.org/html/rfc6901#section-4
        }
    }

    private static JsonNode getPatchAttr(JsonNode jsonNode, String attr) {
        JsonNode child = jsonNode.get(attr);
        if (child == null)
            throw new InvalidJsonPatchException("Invalid JSON Patch payload (missing '" + attr + "' field)");
        return child;
    }

    private static JsonNode getPatchAttrWithDefault(JsonNode jsonNode, String attr, JsonNode defaultValue) {
        JsonNode child = jsonNode.get(attr);
        if (child == null)
            return defaultValue;
        else
            return child;
    }

    private static void process(JsonNode patch, JsonPatchProcessor processor, EnumSet<CompatibilityFlags> flags)
            throws InvalidJsonPatchException {

        if (!patch.isArray())
            throw new InvalidJsonPatchException("Invalid JSON Patch payload (not an array)");
        Iterator<JsonNode> operations = patch.iterator();
        while (operations.hasNext()) {
            JsonNode jsonNode = operations.next();
            if (!jsonNode.isObject())
                throw new InvalidJsonPatchException("Invalid JSON Patch payload (not an object)");
            Operation operation = Operation
                    .fromRfcName(getPatchAttr(jsonNode, Constants.OP).toString().replaceAll("\"", ""));
            List<String> path = getPath(getPatchAttr(jsonNode, Constants.PATH));

            switch (operation) {
            case REMOVE: {
                processor.remove(path);
                break;
            }

            case ADD: {
                JsonNode value;
                if (!flags.contains(CompatibilityFlags.MISSING_VALUES_AS_NULLS))
                    value = getPatchAttr(jsonNode, Constants.VALUE);
                else
                    value = getPatchAttrWithDefault(jsonNode, Constants.VALUE, NullNode.getInstance());
                processor.add(path, value);
                break;
            }

            case REPLACE: {
                JsonNode value;
                if (!flags.contains(CompatibilityFlags.MISSING_VALUES_AS_NULLS))
                    value = getPatchAttr(jsonNode, Constants.VALUE);
                else
                    value = getPatchAttrWithDefault(jsonNode, Constants.VALUE, NullNode.getInstance());
                processor.replace(path, value);
                break;
            }

            case MOVE: {
                List<String> fromPath = getPath(getPatchAttr(jsonNode, Constants.FROM));
                processor.move(fromPath, path);
                break;
            }
            }
        }
    }

    public static void validate(JsonNode patch, EnumSet<CompatibilityFlags> flags)
            throws InvalidJsonPatchException {
        process(patch, NoopProcessor.INSTANCE, flags);
    }

    public static void validate(JsonNode patch) throws InvalidJsonPatchException {
        validate(patch, CompatibilityFlags.defaults());
    }

    public static JsonNode apply(JsonNode patch, JsonNode source, EnumSet<CompatibilityFlags> flags)
            throws JsonPatchApplicationException {
        ApplyProcessor processor = new ApplyProcessor(source);
        process(patch, processor, flags);
        return processor.result();
    }

    public static JsonNode apply(JsonNode patch, JsonNode source) throws JsonPatchApplicationException {
        return apply(patch, source, CompatibilityFlags.defaults());
    }

    private static List<String> getPath(JsonNode path) {
        List<String> paths = Splitter.on('/').splitToList(path.toString().replaceAll("\"", ""));
        return Lists.newArrayList(Iterables.transform(paths, DECODE_PATH_FUNCTION));
    }
}