org.camunda.spin.impl.json.jackson.JacksonJsonNode.java Source code

Java tutorial

Introduction

Here is the source code for org.camunda.spin.impl.json.jackson.JacksonJsonNode.java

Source

/* 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 org.camunda.spin.impl.json.jackson;

import static org.camunda.commons.utils.EnsureUtil.ensureNotNull;

import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.camunda.spin.SpinList;
import org.camunda.spin.impl.SpinListImpl;
import org.camunda.spin.impl.json.jackson.format.JacksonJsonDataFormat;
import org.camunda.spin.impl.json.jackson.format.JacksonJsonDataFormatMapper;
import org.camunda.spin.impl.json.jackson.query.JacksonJsonPathQuery;
import org.camunda.spin.json.SpinJsonDataFormatException;
import org.camunda.spin.json.SpinJsonException;
import org.camunda.spin.json.SpinJsonNode;
import org.camunda.spin.json.SpinJsonPathQuery;
import org.camunda.spin.spi.DataFormatMapper;

import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.JsonNodeType;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.jayway.jsonpath.InvalidPathException;
import com.jayway.jsonpath.JsonPath;

/**
 * Wrapper for a Jackson Json Tree Node.
 *
 * @author Thorben Lindhauer
 * @author Stefan Hentschel
 */
public class JacksonJsonNode extends SpinJsonNode {

    private static final JacksonJsonLogger LOG = JacksonJsonLogger.JSON_TREE_LOGGER;

    protected final JsonNode jsonNode;
    protected final JacksonJsonDataFormat dataFormat;

    public JacksonJsonNode(JsonNode jsonNode, JacksonJsonDataFormat dataFormat) {
        this.jsonNode = jsonNode;
        this.dataFormat = dataFormat;
    }

    public String getDataFormatName() {
        return dataFormat.getName();
    }

    public JsonNode unwrap() {
        return jsonNode;
    }

    public String toString() {
        StringWriter writer = new StringWriter();
        writeToWriter(writer);
        return writer.toString();
    }

    public void writeToWriter(Writer writer) {
        dataFormat.getWriter().writeToWriter(writer, jsonNode);
    }

    /**
     * fetch correct array index if index is less than 0
     *
     * ArrayNode will convert all negative integers into 0...
     *
     * @param index wanted index
     * @return {@link Integer} new index
     */
    protected Integer getCorrectIndex(Integer index) {
        Integer size = jsonNode.size();
        Integer newIndex = index;

        // reverse walking through the array
        if (index < 0) {
            newIndex = size + index;
        }

        // the negative index would be greater than the size a second time!
        if (newIndex < 0) {
            throw LOG.indexOutOfBounds(index, size);
        }

        // the index is greater as the actual size
        if (index > size) {
            throw LOG.indexOutOfBounds(index, size);
        }

        return newIndex;
    }

    public Integer indexOf(Object searchObject) {
        ensureNotNull("searchObject", searchObject);
        if (this.isArray()) {
            Integer i = 0;
            JsonNode node = dataFormat.createJsonNode(searchObject);
            for (Iterator<JsonNode> nodeIterator = jsonNode.elements(); nodeIterator.hasNext(); i++) {
                JsonNode n = nodeIterator.next();
                if (n.equals(node)) {
                    return i;
                }
            }

            // when searchObject is not found
            throw LOG.unableToFindProperty(node.asText());
        } else {
            throw LOG.unableToGetIndex(jsonNode.getNodeType().name());
        }
    }

    public Integer lastIndexOf(Object searchObject) {
        ensureNotNull("searchObject", searchObject);
        if (this.isArray()) {
            Integer i = 0;
            Integer j = -1;
            JsonNode node = dataFormat.createJsonNode(searchObject);
            for (Iterator<JsonNode> nodeIterator = jsonNode.elements(); nodeIterator.hasNext(); i++) {
                JsonNode n = nodeIterator.next();
                if (n.equals(node)) {
                    j = i;
                }
            }

            // when searchObject is not found
            if (j == -1) {
                throw LOG.unableToFindProperty(node.getNodeType().name());
            }

            return j;
        } else {
            throw LOG.unableToGetIndex(jsonNode.getNodeType().name());
        }
    }

    public boolean isObject() {
        return jsonNode.isObject();
    }

    public boolean hasProp(String name) {
        return jsonNode.has(name);
    }

    public SpinJsonNode prop(String name) {
        ensureNotNull("name", name);
        if (jsonNode.has(name)) {
            JsonNode property = jsonNode.get(name);
            return dataFormat.createWrapperInstance(property);
        } else {
            throw LOG.unableToFindProperty(name);
        }
    }

    public SpinJsonNode prop(String name, String newProperty) {
        ObjectNode node = (ObjectNode) jsonNode;

        node.put(name, newProperty);

        return this;
    }

    public SpinJsonNode prop(String name, Number newProperty) {
        ObjectNode node = (ObjectNode) jsonNode;

        // Numbers magic because Jackson has no native .put(Number value)
        if (newProperty instanceof Long) {
            node.put(name, newProperty.longValue());
        } else if (newProperty instanceof Integer) {
            node.put(name, newProperty.intValue());
        } else if (newProperty instanceof Float) {
            node.put(name, newProperty.floatValue());
        } else {
            // convert any other sub class of Number into Float
            node.put(name, newProperty.floatValue());
        }

        return this;
    }

    public SpinJsonNode prop(String name, int newProperty) {
        return prop(name, (Number) newProperty);
    }

    public SpinJsonNode prop(String name, float newProperty) {
        return prop(name, (Number) newProperty);
    }

    public SpinJsonNode prop(String name, long newProperty) {
        return prop(name, (Number) newProperty);
    }

    public SpinJsonNode prop(String name, boolean newProperty) {
        return prop(name, (Boolean) newProperty);
    }

    public SpinJsonNode prop(String name, Boolean newProperty) {
        ObjectNode node = (ObjectNode) jsonNode;

        node.put(name, newProperty);

        return this;
    }

    public SpinJsonNode prop(String name, List<Object> newProperty) {
        ObjectNode node = (ObjectNode) jsonNode;

        node.set(name, dataFormat.createJsonNode(newProperty));

        return this;
    }

    public SpinJsonNode prop(String name, Map<String, Object> newProperty) {
        ObjectNode node = (ObjectNode) jsonNode;

        node.set(name, dataFormat.createJsonNode(newProperty));

        return this;
    }

    public SpinJsonNode prop(String name, SpinJsonNode newProperty) {
        ObjectNode node = (ObjectNode) jsonNode;

        node.set(name, (JsonNode) newProperty.unwrap());

        return this;
    }

    public SpinJsonNode deleteProp(String name) {
        ensureNotNull("name", name);

        if (jsonNode.has(name)) {
            ObjectNode node = (ObjectNode) jsonNode;
            node.remove(name);
            return this;
        } else {
            throw LOG.unableToFindProperty(name);
        }
    }

    public SpinJsonNode deleteProp(List<String> names) {
        ensureNotNull("names", names);

        for (String name : names) {
            deleteProp(name);
        }

        return this;
    }

    public SpinJsonNode append(Object property) {
        ensureNotNull("property", property);
        if (jsonNode.isArray()) {
            ArrayNode node = (ArrayNode) jsonNode;

            node.add(dataFormat.createJsonNode(property));

            return this;
        } else {
            throw LOG.unableToModifyNode(jsonNode.getNodeType().name());
        }
    }

    public SpinJsonNode insertAt(int index, Object property) {
        ensureNotNull("property", property);

        if (jsonNode.isArray()) {
            index = getCorrectIndex(index);
            ArrayNode node = (ArrayNode) jsonNode;

            node.insert(index, dataFormat.createJsonNode(property));

            return this;
        } else {
            throw LOG.unableToModifyNode(jsonNode.getNodeType().name());
        }
    }

    public SpinJsonNode insertBefore(Object searchObject, Object insertObject) {
        ensureNotNull("searchObject", searchObject);
        ensureNotNull("insertObject", insertObject);
        if (this.isArray()) {
            Integer i = indexOf(searchObject);

            return insertAt(i, insertObject);

        } else {
            throw LOG.unableToCreateNode(jsonNode.getNodeType().name());
        }
    }

    public SpinJsonNode insertAfter(Object searchObject, Object insertObject) {
        ensureNotNull("searchObject", searchObject);
        ensureNotNull("insertObject", insertObject);
        if (this.isArray()) {
            Integer i = indexOf(searchObject);

            return insertAt(i + 1, insertObject);

        } else {
            throw LOG.unableToCreateNode(jsonNode.getNodeType().name());
        }
    }

    public SpinJsonNode remove(Object property) {
        return removeAt(indexOf(property));
    }

    public SpinJsonNode removeLast(Object property) {
        return removeAt(lastIndexOf(property));
    }

    public SpinJsonNode removeAt(int index) {
        if (this.isArray()) {
            ArrayNode node = (ArrayNode) jsonNode;

            node.remove(getCorrectIndex(index));

            return this;
        } else {
            throw LOG.unableToModifyNode(jsonNode.getNodeType().name());
        }
    }

    public Boolean isBoolean() {
        return jsonNode.isBoolean();
    }

    public Boolean boolValue() {
        if (jsonNode.isBoolean()) {
            return jsonNode.booleanValue();
        } else {
            throw LOG.unableToParseValue(Boolean.class.getSimpleName(), jsonNode.getNodeType());
        }
    }

    public Boolean isNumber() {
        return jsonNode.isNumber();
    }

    public Number numberValue() {
        if (jsonNode.isNumber()) {
            return jsonNode.numberValue();
        } else {
            throw LOG.unableToParseValue(Number.class.getSimpleName(), jsonNode.getNodeType());
        }
    }

    public Boolean isString() {
        return jsonNode.isTextual();
    }

    public String stringValue() {
        if (jsonNode.isTextual()) {
            return jsonNode.textValue();
        } else {
            throw LOG.unableToParseValue(String.class.getSimpleName(), jsonNode.getNodeType());
        }
    }

    public Boolean isValue() {
        return jsonNode.isValueNode();
    }

    public Object value() {
        if (jsonNode.isBoolean()) {
            return jsonNode.booleanValue();
        }

        if (jsonNode.isNumber()) {
            return jsonNode.numberValue();
        }

        if (jsonNode.isTextual()) {
            return jsonNode.textValue();
        }

        throw LOG.unableToParseValue("String/Number/Boolean", jsonNode.getNodeType());
    }

    public Boolean isArray() {
        return jsonNode.isArray();
    }

    public SpinList<SpinJsonNode> elements() {
        if (jsonNode.isArray()) {
            Iterator<JsonNode> iterator = jsonNode.elements();
            SpinList<SpinJsonNode> list = new SpinListImpl<SpinJsonNode>();
            while (iterator.hasNext()) {
                SpinJsonNode node = dataFormat.createWrapperInstance(iterator.next());
                list.add(node);
            }

            return list;
        } else {
            throw LOG.unableToParseValue(SpinList.class.getSimpleName(), jsonNode.getNodeType());
        }
    }

    public List<String> fieldNames() {
        if (jsonNode.isContainerNode()) {
            Iterator<String> iterator = jsonNode.fieldNames();
            List<String> list = new ArrayList<String>();
            while (iterator.hasNext()) {
                list.add(iterator.next());
            }

            return list;
        } else {
            throw LOG.unableToParseValue("Array/Object", jsonNode.getNodeType());
        }
    }

    public JsonNodeType getNodeType() {
        return jsonNode.getNodeType();
    }

    public SpinJsonPathQuery jsonPath(String expression) {
        ensureNotNull("expression", expression);
        try {
            JsonPath query = JsonPath.compile(expression);
            return new JacksonJsonPathQuery(this, query, dataFormat);
        } catch (InvalidPathException pex) {
            throw LOG.unableToCompileJsonPathExpression(expression, pex);
        } catch (IllegalArgumentException aex) {
            throw LOG.unableToCompileJsonPathExpression(expression, aex);
        }
    }

    /**
     * Maps the json represented by this object to a java object of the given type.
     *
     * @throws SpinJsonException if the json representation cannot be mapped to the specified type
     */
    public <C> C mapTo(Class<C> type) {
        DataFormatMapper mapper = dataFormat.getMapper();
        return mapper.mapInternalToJava(jsonNode, type);
    }

    /**
     * Maps the json represented by this object to a java object of the given type.
     * Argument is to be supplied in Jackson's canonical type string format
     * (see {@link JavaType#toCanonical()}).
     *
     * @throws SpinJsonException if the json representation cannot be mapped to the specified type
     * @throws SpinJsonDataFormatException if the parameter does not match a valid type
     */
    public <C> C mapTo(String type) {
        DataFormatMapper mapper = dataFormat.getMapper();
        return mapper.mapInternalToJava(jsonNode, type);
    }

    /**
     * Maps the json represented by this object to a java object of the given type.
     *
     * @throws SpinJsonException if the json representation cannot be mapped to the specified type
     */
    public <C> C mapTo(JavaType type) {
        JacksonJsonDataFormatMapper mapper = dataFormat.getMapper();
        return mapper.mapInternalToJava(jsonNode, type);
    }
}