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() + ")";
}
}
}