All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.araguacaima.commons.utils.json.parser.JsonPathParser Maven / Gradle / Ivy

package com.araguacaima.commons.utils.json.parser;

import com.araguacaima.commons.utils.ReflectionUtils;
import com.fasterxml.jackson.core.JsonLocation;
import com.fasterxml.jackson.core.JsonParseException;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

/**
 * Parses JSON_PATH
 * expression to construct
 *
 * @param  type of search condition.
 */
public class JsonPathParser {

    private final Beanspector beanspector;
    private SyntaxtNode node;
    private ReflectionUtils reflectionUtils = ReflectionUtils.getInstance();
    ;

    /**
     * Creates Json parser.
     *
     * @param tclass - class of T used to create condition objects in built syntax
     *               tree. Class T must have accessible no-arg constructor and
     *               complementary setters to these used in Json expressions.
     */
    public JsonPathParser(final Class tclass) {
        this(tclass, tclass.getClassLoader());
    }

    public JsonPathParser(Class tClass, ClassLoader classLoader) {
        beanspector = new Beanspector<>(tClass, classLoader);
    }

    public Object getBean() {
        return beanspector.getBean();
    }

    public SyntaxtNode getNode() {
        return node;
    }

    public Class getTclass() {
        return beanspector.getTclass();
    }

    /**
     * Parses expression. Names used in JSON_PATH expression
     * are names of getters/setters in type T.
     *
     * @param jsonPathExpression json path expression.
     * @return tree of {@link T}
     * objects representing runtime structure.
     * @throws JsonParseException     when expression does not follow JSON_PATH grammar
     * @throws InstantiationException when expression does not follow JSON_PATH grammar
     * @throws IllegalAccessException when expression does not follow JSON_PATH grammar
     */
    public Map parse(final String jsonPathExpression)
            throws
            JsonParseException,
            InstantiationException,
            IllegalAccessException {
        this.node = parseDatatype(jsonPathExpression);
        return new HashMap() {{
            put(node.getBean(), node.getField());
        }};
    }

    private SyntaxtNode parseDatatype(final String setter)
            throws JsonParseException, InstantiationException, IllegalAccessException {
        Class firstTokenType;
        Class valueType;
        boolean isCollection = false;
        String methodName;
        String token;
        try {
            final String[] tokens = setter.split("\\.");
            if (tokens.length > 1) {
                token = tokens[0];
                methodName = tokens[1];
            } else {
                token = setter;
                methodName = null;
            }
            firstTokenType = beanspector.getAccessorType(token);
            if (firstTokenType != null) {
                isCollection = reflectionUtils.isCollectionImplementation(firstTokenType);
            }
            valueType = beanspector.getAccessorType(setter);

        } catch (final Exception e) {
            throw new JsonParseException("", JsonLocation.NA, e);
        }

        if (reflectionUtils.isCollectionImplementation(valueType)) {
            valueType = reflectionUtils.createAndInitializeTypedCollection(reflectionUtils.extractGenerics(valueType),
                    null).getClass();
        }

        if (isCollection) {
            try {
                valueType = reflectionUtils.createAndInitializeTypedCollection(firstTokenType, null).getClass();
            } catch (final Exception e) {
                throw new JsonParseException("Cannot set value for attribute '" + methodName + "' of type '" +
                        firstTokenType.getSimpleName() + "' as a part of a collection",
                        JsonLocation.NA,
                        e);
            }
        }
        return new Pair(setter, valueType);
    }

    private class Pair implements SyntaxtNode {
        private final String name;
        private final Class type;

        public Pair(final String name, final Class type) {
            this.name = name;
            this.type = type;
        }

        @Override
        public T getBean() {
            return beanspector.getBean();
        }

        @Override
        public Field getField() {
            return beanspector.getLastTokenField();
        }

        public String getName() {
            return name;
        }

        public Class getType() {
            return type;
        }

        @Override
        public String toString() {
            return name + " " + type + " (" + type.getSimpleName() + ")";
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy