package com.alibaba.fastjson;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.alibaba.fastjson.parser.ParserConfig;
import com.alibaba.fastjson.parser.deserializer.FieldDeserializer;
import com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer;
import com.alibaba.fastjson.parser.deserializer.ObjectDeserializer;
import com.alibaba.fastjson.serializer.FieldSerializer;
import com.alibaba.fastjson.serializer.JavaBeanSerializer;
import com.alibaba.fastjson.serializer.ObjectSerializer;
import com.alibaba.fastjson.serializer.SerializeConfig;
import com.alibaba.fastjson.util.IOUtils;
import com.alibaba.fastjson.util.TypeUtils;
/**
* @author wenshao[szujobs@hotmail.com]
* @since 1.2.0
*/
public class JSONPath implements JSONAware {
private static int CACHE_SIZE = 1024;
private static ConcurrentMap<String, JSONPath> pathCache = new ConcurrentHashMap<String, JSONPath>(128, 0.75f, 1);
private final String path;
private Segement[] segments;
private SerializeConfig serializeConfig;
private ParserConfig parserConfig;
public JSONPath(String path){
this(path, SerializeConfig.getGlobalInstance(), ParserConfig.getGlobalInstance());
}
public JSONPath(String path, SerializeConfig serializeConfig, ParserConfig parserConfig){
if (path == null || path.length() == 0) {
throw new JSONPathException("json-path can not be null or empty");
}
this.path = path;
this.serializeConfig = serializeConfig;
this.parserConfig = parserConfig;
}
protected void init() {
if (segments != null) {
return;
}
if ("*".equals(path)) {
this.segments = new Segement[] { WildCardSegement.instance };
} else {
JSONPathParser parser = new JSONPathParser(path);
this.segments = parser.explain();
}
}
public Object eval(Object rootObject) {
if (rootObject == null) {
return null;
}
init();
Object currentObject = rootObject;
for (int i = 0; i < segments.length; ++i) {
Segement segement = segments[i];
currentObject = segement.eval(this, rootObject, currentObject);
}
return currentObject;
}
public boolean contains(Object rootObject) {
if (rootObject == null) {
return false;
}
init();
Object currentObject = rootObject;
for (int i = 0; i < segments.length; ++i) {
currentObject = segments[i].eval(this, rootObject, currentObject);
if (currentObject == null) {
return false;
}
}
return true;
}
@SuppressWarnings("rawtypes")
public boolean containsValue(Object rootObject, Object value) {
Object currentObject = eval(rootObject);
if (currentObject == value) {
return true;
}
if (currentObject == null) {
return false;
}
if (currentObject instanceof Iterable) {
Iterator it = ((Iterable) currentObject).iterator();
while (it.hasNext()) {
Object item = it.next();
if (eq(item, value)) {
return true;
}
}
return false;
}
return eq(currentObject, value);
}
public int size(Object rootObject) {
if (rootObject == null) {
return -1;
}
init();
Object currentObject = rootObject;
for (int i = 0; i < segments.length; ++i) {
currentObject = segments[i].eval(this, rootObject, currentObject);
}
return evalSize(currentObject);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public void arrayAdd(Object rootObject, Object... values) {
if (values == null || values.length == 0) {
return;
}
if (rootObject == null) {
return;
}
init();
Object currentObject = rootObject;
Object parentObject = null;
for (int i = 0; i < segments.length; ++i) {
if (i == segments.length - 1) {
parentObject = currentObject;
}
currentObject = segments[i].eval(this, rootObject, currentObject);
}
Object result = currentObject;
if (result == null) {
throw new JSONPathException("value not found in path " + path);
}
if (result instanceof Collection) {
Collection collection = (Collection) result;
for (Object value : values) {
collection.add(value);
}
return;
}
Class<?> resultClass = result.getClass();
Object newResult;
if (resultClass.isArray()) {
int length = Array.getLength(result);
Object descArray = Array.newInstance(resultClass.getComponentType(), length + values.length);
System.arraycopy(result, 0, descArray, 0, length);
for (int i = 0; i < values.length; ++i) {
Array.set(descArray, length + i, values[i]);
}
newResult = descArray;
} else {
throw new JSONException("unsupported array put operation. " + resultClass);
}
Segement lastSegement = segments[segments.length - 1];
if (lastSegement instanceof PropertySegement) {
PropertySegement propertySegement = (PropertySegement) lastSegement;
propertySegement.setValue(this, parentObject, newResult);
return;
}
if (lastSegement instanceof ArrayAccessSegement) {
((ArrayAccessSegement) lastSegement).setValue(this, parentObject, newResult);
return;
}
throw new UnsupportedOperationException();
}
public boolean remove(Object rootObject) {
if (rootObject == null) {
return false;
}
init();
Object currentObject = rootObject;
Object parentObject = null;
for (int i = 0; i < segments.length; ++i) {
if (i == segments.length - 1) {
parentObject = currentObject;
break;
}
currentObject = segments[i].eval(this, rootObject, currentObject);
if (currentObject == null) {
break;
}
}
if (parentObject == null) {
return false;
}
Segement lastSegement = segments[segments.length - 1];
if (lastSegement instanceof PropertySegement) {
PropertySegement propertySegement = (PropertySegement) lastSegement;
if (parentObject instanceof Collection) {
if (segments.length > 1) {
Segement parentSegement = segments[segments.length - 2];
if (parentSegement instanceof RangeSegement || parentSegement instanceof MultiIndexSegement) {
Collection collection = (Collection) parentObject;
boolean removedOnce = false;
for (Object item : collection) {
boolean removed = propertySegement.remove(this, item);
if (removed) {
removedOnce = true;
}
}
return removedOnce;
}
}
}
return propertySegement.remove(this, parentObject);
}
if (lastSegement instanceof ArrayAccessSegement) {
return ((ArrayAccessSegement) lastSegement).remove(this, parentObject);
}
throw new UnsupportedOperationException();
}
public boolean set(Object rootObject, Object value) {
return set(rootObject, value, true);
}
public boolean set(Object rootObject, Object value, boolean p) {
if (rootObject == null) {
return false;
}
init();
Object currentObject = rootObject;
Object parentObject = null;
for (int i = 0; i < segments.length; ++i) {
// if (i == segments.length - 1) {
// parentObject = currentObject;
// break;
// }
//
parentObject = currentObject;
Segement segment = segments[i];
currentObject = segment.eval(this, rootObject, currentObject);
if (currentObject == null) {
Segement nextSegement = null;
if (i < segments.length - 1) {
nextSegement = segments[i + 1];
}
Object newObj = null;
if (nextSegement instanceof PropertySegement) {
JavaBeanDeserializer beanDeserializer = null;
Class<?> fieldClass = null;
if (segment instanceof PropertySegement) {
String propertyName = ((PropertySegement) segment).propertyName;
Class<?> parentClass = parentObject.getClass();
JavaBeanDeserializer parentBeanDeserializer = getJavaBeanDeserializer(parentClass);
if (parentBeanDeserializer != null) {
FieldDeserializer fieldDeserializer = parentBeanDeserializer.getFieldDeserializer(propertyName);
fieldClass = fieldDeserializer.fieldInfo.fieldClass;
beanDeserializer = getJavaBeanDeserializer(fieldClass);
}
}
if (beanDeserializer != null) {
if (beanDeserializer.beanInfo.defaultConstructor != null) {
newObj = beanDeserializer.createInstance(null, fieldClass);
} else {
return false;
}
} else {
newObj = new JSONObject();
}
} else if (nextSegement instanceof ArrayAccessSegement) {
newObj = new JSONArray();
}
if (newObj != null) {
if (segment instanceof PropertySegement) {
PropertySegement propSegement = (PropertySegement) segment;
propSegement.setValue(this, parentObject, newObj);
currentObject = newObj;
continue;
} else if (segment instanceof ArrayAccessSegement) {
ArrayAccessSegement arrayAccessSegement = (ArrayAccessSegement) segment;
arrayAccessSegement.setValue(this, parentObject, newObj);
currentObject = newObj;
continue;
}
}
break;
}
}
if (parentObject == null) {
return false;
}
Segement lastSegement = segments[segments.length - 1];
if (lastSegement instanceof PropertySegement) {
PropertySegement propertySegement = (PropertySegement) lastSegement;
propertySegement.setValue(this, parentObject, value);
return true;
}
if (lastSegement instanceof ArrayAccessSegement) {
return ((ArrayAccessSegement) lastSegement).setValue(this, parentObject, value);
}
throw new UnsupportedOperationException();
}
public static Object eval(Object rootObject, String path) {
JSONPath jsonpath = compile(path);
return jsonpath.eval(rootObject);
}
public static int size(Object rootObject, String path) {
JSONPath jsonpath = compile(path);
Object result = jsonpath.eval(rootObject);
return jsonpath.evalSize(result);
}
public static boolean contains(Object rootObject, String path) {
if (rootObject == null) {
return false;
}
JSONPath jsonpath = compile(path);
return jsonpath.contains(rootObject);
}
public static boolean containsValue(Object rootObject, String path, Object value) {
JSONPath jsonpath = compile(path);
return jsonpath.containsValue(rootObject, value);
}
public static void arrayAdd(Object rootObject, String path, Object... values) {
JSONPath jsonpath = compile(path);
jsonpath.arrayAdd(rootObject, values);
}
public static boolean set(Object rootObject, String path, Object value) {
JSONPath jsonpath = compile(path);
return jsonpath.set(rootObject, value);
}
public static boolean remove(Object root, String path) {
JSONPath jsonpath = compile(path);
return jsonpath.remove(root);
}
public static JSONPath compile(String path) {
if (path == null) {
throw new JSONPathException("jsonpath can not be null");
}
JSONPath jsonpath = pathCache.get(path);
if (jsonpath == null) {
jsonpath = new JSONPath(path);
if (pathCache.size() < CACHE_SIZE) {
pathCache.putIfAbsent(path, jsonpath);
jsonpath = pathCache.get(path);
}
}
return jsonpath;
}
/**
* @since 1.2.9
* @param json
* @param path
* @return
*/
public static Object read(String json, String path) {
Object object = JSON.parse(json);
JSONPath jsonpath = compile(path);
return jsonpath.eval(object);
}
public static Map<String, Object> paths(Object javaObject) {
return paths(javaObject, SerializeConfig.globalInstance);
}
public static Map<String, Object> paths(Object javaObject, SerializeConfig config) {
Map<Object, String> values = new IdentityHashMap<Object, String>();
paths(values, "/", javaObject, config);
Map<String, Object> paths = new HashMap<String, Object>();
for (Map.Entry<Object, String> entry : values.entrySet()) {
paths.put(entry.getValue(), entry.getKey());
}
return paths;
}
@SuppressWarnings("rawtypes")
private static void paths(Map<Object, String> paths, String parent, Object javaObject, SerializeConfig config) {
if (javaObject == null) {
return;
}
if (paths.containsKey(javaObject)) {
return;
}
paths.put(javaObject, parent);
if (javaObject instanceof Map) {
Map map = (Map) javaObject;
for (Object entryObj : map.entrySet()) {
Map.Entry entry = (Map.Entry) entryObj;
Object key = entry.getKey();
if (key instanceof String) {
String path = parent.equals("/") ? "/" + key : parent + "/" + key;
paths(paths, path, entry.getValue(), config);
}
}
return;
}
if (javaObject instanceof Collection) {
Collection collection = (Collection) javaObject;
int i = 0;
for (Object item : collection) {
String path = parent.equals("/") ? "/" + i : parent + "/" + i;
paths(paths, path, item, config);
++i;
}
return;
}
Class<?> clazz = javaObject.getClass();
if (clazz.isArray()) {
int len = Array.getLength(javaObject);
for (int i = 0; i < len; ++i) {
Object item = Array.get(javaObject, i);
String path = parent.equals("/") ? "/" + i : parent + "/" + i;
paths(paths, path, item, config);
}
return;
}
if (ParserConfig.isPrimitive2(clazz) || clazz.isEnum()) {
return;
}
ObjectSerializer serializer = config.getObjectWriter(clazz);
if (serializer instanceof JavaBeanSerializer) {
JavaBeanSerializer javaBeanSerializer = (JavaBeanSerializer) serializer;
try {
Map<String, Object> fieldValues = javaBeanSerializer.getFieldValuesMap(javaObject);
for (Map.Entry<String, Object> entry : fieldValues.entrySet()) {
String key = entry.getKey();
if (key instanceof String) {
String path = parent.equals("/") ? "/" + key : parent + "/" + key;
paths(paths, path, entry.getValue(), config);
}
}
} catch (Exception e) {
throw new JSONException("toJSON error", e);
}
return;
}
return;
}
public String getPath() {
return path;
}
static class JSONPathParser {
private final String path;
private int pos;
private char ch;
private int level;
public JSONPathParser(String path){
this.path = path;
next();
}
void next() {
ch = path.charAt(pos++);
}
boolean isEOF() {
return pos >= path.length();
}
Segement readSegement() {
if (level == 0 && path.length() == 1) {
if (isDigitFirst(ch)) {
int index = ch - '0';
return new ArrayAccessSegement(index);
} else if ((ch >= 'a' && ch <= 'z') || ((ch >= 'A' && ch <= 'Z'))) {
return new PropertySegement(Character.toString(ch), false);
}
}
while (!isEOF()) {
skipWhitespace();
if (ch == '$') {
next();
continue;
}
if (ch == '.' || ch == '/') {
int c0 = ch;
boolean deep = false;
next();
if (c0 == '.' && ch == '.') {
next();
deep = true;
}
if (ch == '*') {
if (!isEOF()) {
next();
}
return WildCardSegement.instance;
}
if (isDigitFirst(ch)) {
return parseArrayAccess(false);
}
String propertyName = readName();
if (ch == '(') {
next();
if (ch == ')') {
if (!isEOF()) {
next();
}
if ("size".equals(propertyName)) {
return SizeSegement.instance;
}
throw new UnsupportedOperationException();
}
throw new UnsupportedOperationException();
}
return new PropertySegement(propertyName, deep);
}
if (ch == '[') {
return parseArrayAccess(true);
}
if (level == 0) {
String propertyName = readName();
return new PropertySegement(propertyName, false);
}
throw new UnsupportedOperationException();
}
return null;
}
public final void skipWhitespace() {
for (;;) {
if (ch <= ' ' && (ch == ' ' || ch == '\r' || ch == '\n' || ch == '\t' || ch == '\f' || ch == '\b')) {
next();
continue;
} else {
break;
}
}
}
Segement parseArrayAccess(boolean acceptBracket) {
if (acceptBracket) {
accept('[');
}
boolean predicateFlag = false;
if (ch == '?') {
next();
accept('(');
if (ch == '@') {
next();
accept('.');
}
predicateFlag = true;
}
if (predicateFlag || IOUtils.firstIdentifier(ch)) {
String propertyName = readName();
skipWhitespace();
if (predicateFlag && ch == ')') {
next();
if (acceptBracket) {
accept(']');
}
return new FilterSegement(new NotNullSegement(propertyName));
}
if (acceptBracket && ch == ']') {
next();
return new FilterSegement(new NotNullSegement(propertyName));
}
Operator op = readOp();
skipWhitespace();
if (op == Operator.BETWEEN || op == Operator.NOT_BETWEEN) {
final boolean not = (op == Operator.NOT_BETWEEN);
Object startValue = readValue();
String name = readName();
if (!"and".equalsIgnoreCase(name)) {
throw new JSONPathException(path);
}
Object endValue = readValue();
if (startValue == null || endValue == null) {
throw new JSONPathException(path);
}
if (isInt(startValue.getClass()) && isInt(endValue.getClass())) {
Filter filter = new IntBetweenSegement(propertyName, ((Number) startValue).longValue(),
((Number) endValue).longValue(), not);
return new FilterSegement(filter);
}
throw new JSONPathException(path);
}
if (op == Operator.IN || op == Operator.NOT_IN) {
final boolean not = (op == Operator.NOT_IN);
accept('(');
List<Object> valueList = new JSONArray();
{
Object value = readValue();
valueList.add(value);
for (;;) {
skipWhitespace();
if (ch != ',') {
break;
}
next();
value = readValue();
valueList.add(value);
}
accept(')');
if (predicateFlag) {
accept(')');
}
if (acceptBracket) {
accept(']');
}
}
boolean isInt = true;
boolean isIntObj = true;
boolean isString = true;
for (Object item : valueList) {
if (item == null) {
if (isInt) {
isInt = false;
}
continue;
}
Class<?> clazz = item.getClass();
if (isInt && !(clazz == Byte.class || clazz == Short.class || clazz == Integer.class
|| clazz == Long.class)) {
isInt = false;
isIntObj = false;
}
if (isString && clazz != String.class) {
isString = false;
}
}
if (valueList.size() == 1 && valueList.get(0) == null) {
if (not) {
return new FilterSegement(new NotNullSegement(propertyName));
} else {
return new FilterSegement(new NullSegement(propertyName));
}
}
if (isInt) {
if (valueList.size() == 1) {
long value = ((Number) valueList.get(0)).longValue();
Operator intOp = not ? Operator.NE : Operator.EQ;
return new FilterSegement(new IntOpSegement(propertyName, value, intOp));
}
long[] values = new long[valueList.size()];
for (int i = 0; i < values.length; ++i) {
values[i] = ((Number) valueList.get(i)).longValue();
}
return new FilterSegement(new IntInSegement(propertyName, values, not));
}
if (isString) {
if (valueList.size() == 1) {
String value = (String) valueList.get(0);
Operator intOp = not ? Operator.NE : Operator.EQ;
return new FilterSegement(new StringOpSegement(propertyName, value, intOp));
}
String[] values = new String[valueList.size()];
valueList.toArray(values);
return new FilterSegement(new StringInSegement(propertyName, values, not));
}
if (isIntObj) {
Long[] values = new Long[valueList.size()];
for (int i = 0; i < values.length; ++i) {
Number item = (Number) valueList.get(i);
if (item != null) {
values[i] = item.longValue();
}
}
return new FilterSegement(new IntObjInSegement(propertyName, values, not));
}
throw new UnsupportedOperationException();
}
if (ch == '\'' || ch == '"') {
String strValue = readString();
if (predicateFlag) {
accept(')');
}
if (acceptBracket) {
accept(']');
}
if (op == Operator.RLIKE) {
return new FilterSegement(new RlikeSegement(propertyName, strValue, false));
}
if (op == Operator.NOT_RLIKE) {
return new FilterSegement(new RlikeSegement(propertyName, strValue, true));
}
if (op == Operator.LIKE || op == Operator.NOT_LIKE) {
while (strValue.indexOf("%%") != -1) {
strValue = strValue.replaceAll("%%", "%");
}
final boolean not = (op == Operator.NOT_LIKE);
int p0 = strValue.indexOf('%');
if (p0 == -1) {
if (op == Operator.LIKE) {
op = Operator.EQ;
} else {
op = Operator.NE;
}
} else {
String[] items = strValue.split("%");
String startsWithValue = null;
String endsWithValue = null;
String[] containsValues = null;
if (p0 == 0) {
if (strValue.charAt(strValue.length() - 1) == '%') {
containsValues = new String[items.length - 1];
System.arraycopy(items, 1, containsValues, 0, containsValues.length);
} else {
endsWithValue = items[items.length - 1];
if (items.length > 2) {
containsValues = new String[items.length - 2];
System.arraycopy(items, 1, containsValues, 0, containsValues.length);
}
}
} else if (strValue.charAt(strValue.length() - 1) == '%') {
containsValues = items;
} else {
if (items.length == 1) {
startsWithValue = items[0];
} else if (items.length == 2) {
startsWithValue = items[0];
endsWithValue = items[1];
} else {
startsWithValue = items[0];
endsWithValue = items[items.length - 1];
containsValues = new String[items.length - 2];
System.arraycopy(items, 1, containsValues, 0, containsValues.length);
}
}
return new FilterSegement(new MatchSegement(propertyName, startsWithValue, endsWithValue,
containsValues, not));
}
}
return new FilterSegement(new StringOpSegement(propertyName, strValue, op));
}
if (isDigitFirst(ch)) {
long value = readLongValue();
double doubleValue = 0D;
if (ch == '.') {
doubleValue = readDoubleValue(value);
}
if (predicateFlag) {
accept(')');
}
if (acceptBracket) {
accept(']');
}
if (doubleValue == 0) {
return new FilterSegement(new IntOpSegement(propertyName, value, op));
} else {
return new FilterSegement(new DoubleOpSegement(propertyName, doubleValue, op));
}
}
if (ch == 'n') {
String name = readName();
if ("null".equals(name)) {
if (predicateFlag) {
accept(')');
}
accept(']');
if (op == Operator.EQ) {
return new FilterSegement(new NullSegement(propertyName));
}
if (op == Operator.NE) {
return new FilterSegement(new NotNullSegement(propertyName));
}
throw new UnsupportedOperationException();
}
} else if (ch == 't') {
String name = readName();
if ("true".equals(name)) {
if (predicateFlag) {
accept(')');
}
accept(']');
if (op == Operator.EQ) {
return new FilterSegement(new ValueSegment(propertyName, Boolean.TRUE, true));
}
if (op == Operator.NE) {
return new FilterSegement(new ValueSegment(propertyName, Boolean.TRUE, false));
}
throw new UnsupportedOperationException();
}
} else if (ch == 'f') {
String name = readName();
if ("false".equals(name)) {
if (predicateFlag) {
accept(')');
}
accept(']');
if (op == Operator.EQ) {
return new FilterSegement(new ValueSegment(propertyName, Boolean.FALSE, true));
}
if (op == Operator.NE) {
return new FilterSegement(new ValueSegment(propertyName, Boolean.FALSE, false));
}
throw new UnsupportedOperationException();
}
}
throw new UnsupportedOperationException();
// accept(')');
}
int start = pos - 1;
while (ch != ']' && ch != '/' && !isEOF()) {
if (ch == '.' //
&& (!predicateFlag) //
&& !predicateFlag) {
break;
}
if (ch == '\\') {
next();
}
next();
}
int end;
if (acceptBracket) {
end = pos - 1;
} else {
if (ch == '/' || ch == '.') {
end = pos - 1;
} else {
end = pos;
}
}
String text = path.substring(start, end);
if (text.indexOf("\\.") != -1) {
String propName = text.replaceAll("\\\\\\.","\\.");
return new PropertySegement(propName, false);
}
Segement segment = buildArraySegement(text);
if (acceptBracket && !isEOF()) {
accept(']');
}
return segment;
}
protected long readLongValue() {
int beginIndex = pos - 1;
if (ch == '+' || ch == '-') {
next();
}
while (ch >= '0' && ch <= '9') {
next();
}
int endIndex = pos - 1;
String text = path.substring(beginIndex, endIndex);
long value = Long.parseLong(text);
return value;
}
protected double readDoubleValue(long longValue) {
int beginIndex = pos - 1;
next();
while (ch >= '0' && ch <= '9') {
next();
}
int endIndex = pos - 1;
String text = path.substring(beginIndex, endIndex);
double value = Double.parseDouble(text);
value += longValue;
return value;
}
protected Object readValue() {
skipWhitespace();
if (isDigitFirst(ch)) {
return readLongValue();
}
if (ch == '"' || ch == '\'') {
return readString();
}
if (ch == 'n') {
String name = readName();
if ("null".equals(name)) {
return null;
} else {
throw new JSONPathException(path);
}
}
throw new UnsupportedOperationException();
}
static boolean isDigitFirst(char ch) {
return ch == '-' || ch == '+' || (ch >= '0' && ch <= '9');
}
protected Operator readOp() {
Operator op = null;
if (ch == '=') {
next();
op = Operator.EQ;
} else if (ch == '!') {
next();
accept('=');
op = Operator.NE;
} else if (ch == '<') {
next();
if (ch == '=') {
next();
op = Operator.LE;
} else {
op = Operator.LT;
}
} else if (ch == '>') {
next();
if (ch == '=') {
next();
op = Operator.GE;
} else {
op = Operator.GT;
}
}
if (op == null) {
String name = readName();
if ("not".equalsIgnoreCase(name)) {
skipWhitespace();
name = readName();
if ("like".equalsIgnoreCase(name)) {
op = Operator.NOT_LIKE;
} else if ("rlike".equalsIgnoreCase(name)) {
op = Operator.NOT_RLIKE;
} else if ("in".equalsIgnoreCase(name)) {
op = Operator.NOT_IN;
} else if ("between".equalsIgnoreCase(name)) {
op = Operator.NOT_BETWEEN;
} else {
throw new UnsupportedOperationException();
}
} else {
if ("like".equalsIgnoreCase(name)) {
op = Operator.LIKE;
} else if ("rlike".equalsIgnoreCase(name)) {
op = Operator.RLIKE;
} else if ("in".equalsIgnoreCase(name)) {
op = Operator.IN;
} else if ("between".equalsIgnoreCase(name)) {
op = Operator.BETWEEN;
} else {
throw new UnsupportedOperationException();
}
}
}
return op;
}
String readName() {
skipWhitespace();
if (ch != '\\' && !IOUtils.firstIdentifier(ch)) {
throw new JSONPathException("illeal jsonpath syntax. " + path);
}
StringBuilder buf = new StringBuilder();
while (!isEOF()) {
if (ch == '\\') {
next();
buf.append(ch);
if (isEOF()) {
break;
}
next();
continue;
}
boolean identifierFlag = IOUtils.isIdent(ch);
if (!identifierFlag) {
break;
}
buf.append(ch);
next();
}
if (isEOF() && IOUtils.isIdent(ch)) {
buf.append(ch);
}
String propertyName = buf.toString();
return propertyName;
}
String readString() {
char quoate = ch;
next();
int beginIndex = pos - 1;
while (ch != quoate && !isEOF()) {
next();
}
String strValue = path.substring(beginIndex, isEOF() ? pos : pos - 1);
accept(quoate);
return strValue;
}
void accept(char expect) {
if (ch != expect) {
throw new JSONPathException("expect '" + expect + ", but '" + ch + "'");
}
if (!isEOF()) {
next();
}
}
public Segement[] explain() {
if (path == null || path.length() == 0) {
throw new IllegalArgumentException();
}
Segement[] segements = new Segement[8];
for (;;) {
Segement segment = readSegement();
if (segment == null) {
break;
}
if (level == segements.length) {
Segement[] t = new Segement[level * 3 / 2];
System.arraycopy(segements, 0, t, 0, level);
segements = t;
}
segements[level++] = segment;
}
if (level == segements.length) {
return segements;
}
Segement[] result = new Segement[level];
System.arraycopy(segements, 0, result, 0, level);
return result;
}
Segement buildArraySegement(String indexText) {
final int indexTextLen = indexText.length();
final char firstChar = indexText.charAt(0);
final char lastChar = indexText.charAt(indexTextLen - 1);
int commaIndex = indexText.indexOf(',');
if (indexText.length() > 2 && firstChar == '\'' && lastChar == '\'') {
if (commaIndex == -1) {
String propertyName = indexText.substring(1, indexTextLen - 1);
return new PropertySegement(propertyName, false);
}
String[] indexesText = indexText.split(",");
String[] propertyNames = new String[indexesText.length];
for (int i = 0; i < indexesText.length; ++i) {
String indexesTextItem = indexesText[i];
propertyNames[i] = indexesTextItem.substring(1, indexesTextItem.length() - 1);
}
return new MultiPropertySegement(propertyNames);
}
int colonIndex = indexText.indexOf(':');
if (commaIndex == -1 && colonIndex == -1) {
if (TypeUtils.isNumber(indexText)) {
int index = Integer.parseInt(indexText);
return new ArrayAccessSegement(index);
} else {
return new PropertySegement(indexText, false);
}
}
if (commaIndex != -1) {
String[] indexesText = indexText.split(",");
int[] indexes = new int[indexesText.length];
for (int i = 0; i < indexesText.length; ++i) {
indexes[i] = Integer.parseInt(indexesText[i]);
}
return new MultiIndexSegement(indexes);
}
if (colonIndex != -1) {
String[] indexesText = indexText.split(":");
int[] indexes = new int[indexesText.length];
for (int i = 0; i < indexesText.length; ++i) {
String str = indexesText[i];
if (str.length() == 0) {
if (i == 0) {
indexes[i] = 0;
} else {
throw new UnsupportedOperationException();
}
} else {
indexes[i] = Integer.parseInt(str);
}
}
int start = indexes[0];
int end;
if (indexes.length > 1) {
end = indexes[1];
} else {
end = -1;
}
int step;
if (indexes.length == 3) {
step = indexes[2];
} else {
step = 1;
}
if (end >= 0 && end < start) {
throw new UnsupportedOperationException("end must greater than or equals start. start " + start
+ ", end " + end);
}
if (step <= 0) {
throw new UnsupportedOperationException("step must greater than zero : " + step);
}
return new RangeSegement(start, end, step);
}
throw new UnsupportedOperationException();
}
}
interface Segement {
Object eval(JSONPath path, Object rootObject, Object currentObject);
}
static class SizeSegement implements Segement {
public final static SizeSegement instance = new SizeSegement();
public Integer eval(JSONPath path, Object rootObject, Object currentObject) {
return path.evalSize(currentObject);
}
}
static class PropertySegement implements Segement {
private final String propertyName;
private final boolean deep;
public PropertySegement(String propertyName, boolean deep){
this.propertyName = propertyName;
this.deep = deep;
}
public Object eval(JSONPath path, Object rootObject, Object currentObject) {
if (deep) {
List<Object> results = new ArrayList<Object>();
path.deepScan(currentObject, propertyName, results);
return results;
} else {
return path.getPropertyValue(currentObject, propertyName, true);
}
}
public void setValue(JSONPath path, Object parent, Object value) {
if (deep) {
path.deepSet(parent, propertyName, value);
} else {
path.setPropertyValue(parent, propertyName, value);
}
}
public boolean remove(JSONPath path, Object parent) {
return path.removePropertyValue(parent, propertyName);
}
}
static class MultiPropertySegement implements Segement {
private final String[] propertyNames;
public MultiPropertySegement(String[] propertyNames){
this.propertyNames = propertyNames;
}
public Object eval(JSONPath path, Object rootObject, Object currentObject) {
List<Object> fieldValues = new ArrayList<Object>(propertyNames.length);
for (String propertyName : propertyNames) {
Object fieldValue = path.getPropertyValue(currentObject, propertyName, true);
fieldValues.add(fieldValue);
}
return fieldValues;
}
}
static class WildCardSegement implements Segement {
public static WildCardSegement instance = new WildCardSegement();
public Object eval(JSONPath path, Object rootObject, Object currentObject) {
return path.getPropertyValues(currentObject);
}
}
static class ArrayAccessSegement implements Segement {
private final int index;
public ArrayAccessSegement(int index){
this.index = index;
}
public Object eval(JSONPath path, Object rootObject, Object currentObject) {
return path.getArrayItem(currentObject, index);
}
public boolean setValue(JSONPath path, Object currentObject, Object value) {
return path.setArrayItem(path, currentObject, index, value);
}
public boolean remove(JSONPath path, Object currentObject) {
return path.removeArrayItem(path, currentObject, index);
}
}
static class MultiIndexSegement implements Segement {
private final int[] indexes;
public MultiIndexSegement(int[] indexes){
this.indexes = indexes;
}
public Object eval(JSONPath path, Object rootObject, Object currentObject) {
List<Object> items = new ArrayList<Object>(indexes.length);
for (int i = 0; i < indexes.length; ++i) {
Object item = path.getArrayItem(currentObject, indexes[i]);
items.add(item);
}
return items;
}
}
static class RangeSegement implements Segement {
private final int start;
private final int end;
private final int step;
public RangeSegement(int start, int end, int step){
this.start = start;
this.end = end;
this.step = step;
}
public Object eval(JSONPath path, Object rootObject, Object currentObject) {
int size = SizeSegement.instance.eval(path, rootObject, currentObject);
int start = this.start >= 0 ? this.start : this.start + size;
int end = this.end >= 0 ? this.end : this.end + size;
int array_size = (end - start) / step + 1;
if (array_size == -1) {
return null;
}
List<Object> items = new ArrayList<Object>(array_size);
for (int i = start; i <= end && i < size; i += step) {
Object item = path.getArrayItem(currentObject, i);
items.add(item);
}
return items;
}
}
static class NotNullSegement implements Filter {
private final String propertyName;
public NotNullSegement(String propertyName){
this.propertyName = propertyName;
}
public boolean apply(JSONPath path, Object rootObject, Object currentObject, Object item) {
Object propertyValue = path.getPropertyValue(item, propertyName, false);
return propertyValue != null;
}
}
static class NullSegement implements Filter {
private final String propertyName;
public NullSegement(String propertyName){
this.propertyName = propertyName;
}
public boolean apply(JSONPath path, Object rootObject, Object currentObject, Object item) {
Object propertyValue = path.getPropertyValue(item, propertyName, false);
return propertyValue == null;
}
}
static class ValueSegment implements Filter {
private final String propertyName;
private final Object value;
private boolean eq = true;
public ValueSegment(String propertyName, Object value, boolean eq){
if (value == null) {
throw new IllegalArgumentException("value is null");
}
this.propertyName = propertyName;
this.value = value;
this.eq = eq;
}
public boolean apply(JSONPath path, Object rootObject, Object currentObject, Object item) {
Object propertyValue = path.getPropertyValue(item, propertyName, false);
boolean result = value.equals(propertyValue);
if (!eq) {
result = !result;
}
return result;
}
}
static class IntInSegement implements Filter {
private final String propertyName;
private final long[] values;
private final boolean not;
public IntInSegement(String propertyName, long[] values, boolean not){
this.propertyName = propertyName;
this.values = values;
this.not = not;
}
public boolean apply(JSONPath path, Object rootObject, Object currentObject, Object item) {
Object propertyValue = path.getPropertyValue(item, propertyName, false);
if (propertyValue == null) {
return false;
}
if (propertyValue instanceof Number) {
long longPropertyValue = ((Number) propertyValue).longValue();
for (long value : values) {
if (value == longPropertyValue) {
return !not;
}
}
}
return not;
}
}
static class IntBetweenSegement implements Filter {
private final String propertyName;
private final long startValue;
private final long endValue;
private final boolean not;
public IntBetweenSegement(String propertyName, long startValue, long endValue, boolean not){
this.propertyName = propertyName;
this.startValue = startValue;
this.endValue = endValue;
this.not = not;
}
public boolean apply(JSONPath path, Object rootObject, Object currentObject, Object item) {
Object propertyValue = path.getPropertyValue(item, propertyName, false);
if (propertyValue == null) {
return false;
}
if (propertyValue instanceof Number) {
long longPropertyValue = ((Number) propertyValue).longValue();
if (longPropertyValue >= startValue && longPropertyValue <= endValue) {
return !not;
}
}
return not;
}
}
static class IntObjInSegement implements Filter {
private final String propertyName;
private final Long[] values;
private final boolean not;
public IntObjInSegement(String propertyName, Long[] values, boolean not){
this.propertyName = propertyName;
this.values = values;
this.not = not;
}
public boolean apply(JSONPath path, Object rootObject, Object currentObject, Object item) {
Object propertyValue = path.getPropertyValue(item, propertyName, false);
if (propertyValue == null) {
for (Long value : values) {
if (value == null) {
return !not;
}
}
return not;
}
if (propertyValue instanceof Number) {
long longPropertyValue = ((Number) propertyValue).longValue();
for (Long value : values) {
if (value == null) {
continue;
}
if (value.longValue() == longPropertyValue) {
return !not;
}
}
}
return not;
}
}
static class StringInSegement implements Filter {
private final String propertyName;
private final String[] values;
private final boolean not;
public StringInSegement(String propertyName, String[] values, boolean not){
this.propertyName = propertyName;
this.values = values;
this.not = not;
}
public boolean apply(JSONPath path, Object rootObject, Object currentObject, Object item) {
Object propertyValue = path.getPropertyValue(item, propertyName, false);
for (String value : values) {
if (value == propertyValue) {
return !not;
} else if (value != null && value.equals(propertyValue)) {
return !not;
}
}
return not;
}
}
static class IntOpSegement implements Filter {
private final String propertyName;
private final long value;
private final Operator op;
public IntOpSegement(String propertyName, long value, Operator op){
this.propertyName = propertyName;
this.value = value;
this.op = op;
}
public boolean apply(JSONPath path, Object rootObject, Object currentObject, Object item) {
Object propertyValue = path.getPropertyValue(item, propertyName, false);
if (propertyValue == null) {
return false;
}
if (!(propertyValue instanceof Number)) {
return false;
}
long longValue = ((Number) propertyValue).longValue();
if (op == Operator.EQ) {
return longValue == value;
} else if (op == Operator.NE) {
return longValue != value;
} else if (op == Operator.GE) {
return longValue >= value;
} else if (op == Operator.GT) {
return longValue > value;
} else if (op == Operator.LE) {
return longValue <= value;
} else if (op == Operator.LT) {
return longValue < value;
}
return false;
}
}
static class DoubleOpSegement implements Filter {
private final String propertyName;
private final double value;
private final Operator op;
public DoubleOpSegement(String propertyName, double value, Operator op){
this.propertyName = propertyName;
this.value = value;
this.op = op;
}
public boolean apply(JSONPath path, Object rootObject, Object currentObject, Object item) {
Object propertyValue = path.getPropertyValue(item, propertyName, false);
if (propertyValue == null) {
return false;
}
if (!(propertyValue instanceof Number)) {
return false;
}
double doubleValue = ((Number) propertyValue).doubleValue();
if (op == Operator.EQ) {
return doubleValue == value;
} else if (op == Operator.NE) {
return doubleValue != value;
} else if (op == Operator.GE) {
return doubleValue >= value;
} else if (op == Operator.GT) {
return doubleValue > value;
} else if (op == Operator.LE) {
return doubleValue <= value;
} else if (op == Operator.LT) {
return doubleValue < value;
}
return false;
}
}
static class MatchSegement implements Filter {
private final String propertyName;
private final String startsWithValue;
private final String endsWithValue;
private final String[] containsValues;
private final int minLength;
private final boolean not;
public MatchSegement(String propertyName, String startsWithValue, String endsWithValue, String[] containsValues,
boolean not){
this.propertyName = propertyName;
this.startsWithValue = startsWithValue;
this.endsWithValue = endsWithValue;
this.containsValues = containsValues;
this.not = not;
int len = 0;
if (startsWithValue != null) {
len += startsWithValue.length();
}
if (endsWithValue != null) {
len += endsWithValue.length();
}
if (containsValues != null) {
for (String item : containsValues) {
len += item.length();
}
}
this.minLength = len;
}
public boolean apply(JSONPath path, Object rootObject, Object currentObject, Object item) {
Object propertyValue = path.getPropertyValue(item, propertyName, false);
if (propertyValue == null) {
return false;
}
final String strPropertyValue = propertyValue.toString();
if (strPropertyValue.length() < minLength) {
return not;
}
int start = 0;
if (startsWithValue != null) {
if (!strPropertyValue.startsWith(startsWithValue)) {
return not;
}
start += startsWithValue.length();
}
if (containsValues != null) {
for (String containsValue : containsValues) {
int index = strPropertyValue.indexOf(containsValue, start);
if (index == -1) {
return not;
}
start = index + containsValue.length();
}
}
if (endsWithValue != null) {
if (!strPropertyValue.endsWith(endsWithValue)) {
return not;
}
}
return !not;
}
}
static class RlikeSegement implements Filter {
private final String propertyName;
private final Pattern pattern;
private final boolean not;
public RlikeSegement(String propertyName, String pattern, boolean not){
this.propertyName = propertyName;
this.pattern = Pattern.compile(pattern);
this.not = not;
}
public boolean apply(JSONPath path, Object rootObject, Object currentObject, Object item) {
Object propertyValue = path.getPropertyValue(item, propertyName, false);
if (propertyValue == null) {
return false;
}
String strPropertyValue = propertyValue.toString();
Matcher m = pattern.matcher(strPropertyValue);
boolean match = m.matches();
if (not) {
match = !match;
}
return match;
}
}
static class StringOpSegement implements Filter {
private final String propertyName;
private final String value;
private final Operator op;
public StringOpSegement(String propertyName, String value, Operator op){
this.propertyName = propertyName;
this.value = value;
this.op = op;
}
public boolean apply(JSONPath path, Object rootObject, Object currentObject, Object item) {
Object propertyValue = path.getPropertyValue(item, propertyName, false);
if (op == Operator.EQ) {
return value.equals(propertyValue);
} else if (op == Operator.NE) {
return !value.equals(propertyValue);
}
if (propertyValue == null) {
return false;
}
int compareResult = value.compareTo(propertyValue.toString());
if (op == Operator.GE) {
return compareResult <= 0;
} else if (op == Operator.GT) {
return compareResult < 0;
} else if (op == Operator.LE) {
return compareResult >= 0;
} else if (op == Operator.LT) {
return compareResult > 0;
}
return false;
}
}
enum Operator {
EQ, NE, GT, GE, LT, LE, LIKE, NOT_LIKE, RLIKE, NOT_RLIKE, IN, NOT_IN, BETWEEN, NOT_BETWEEN
}
static public class FilterSegement implements Segement {
private final Filter filter;
public FilterSegement(Filter filter){
super();
this.filter = filter;
}
@SuppressWarnings("rawtypes")
public Object eval(JSONPath path, Object rootObject, Object currentObject) {
if (currentObject == null) {
return null;
}
List<Object> items = new JSONArray();
if (currentObject instanceof Iterable) {
Iterator it = ((Iterable) currentObject).iterator();
while (it.hasNext()) {
Object item = it.next();
if (filter.apply(path, rootObject, currentObject, item)) {
items.add(item);
}
}
return items;
}
if (filter.apply(path, rootObject, currentObject, currentObject)) {
return currentObject;
}
return null;
}
}
interface Filter {
boolean apply(JSONPath path, Object rootObject, Object currentObject, Object item);
}
@SuppressWarnings("rawtypes")
protected Object getArrayItem(final Object currentObject, int index) {
if (currentObject == null) {
return null;
}
if (currentObject instanceof List) {
List list = (List) currentObject;
if (index >= 0) {
if (index < list.size()) {
return list.get(index);
}
return null;
} else {
if (Math.abs(index) <= list.size()) {
return list.get(list.size() + index);
}
return null;
}
}
if (currentObject.getClass().isArray()) {
int arrayLenth = Array.getLength(currentObject);
if (index >= 0) {
if (index < arrayLenth) {
return Array.get(currentObject, index);
}
return null;
} else {
if (Math.abs(index) <= arrayLenth) {
return Array.get(currentObject, arrayLenth + index);
}
return null;
}
}
if (currentObject instanceof Map) {
Map map = (Map) currentObject;
Object value = map.get(index);
if (value == null) {
value = map.get(Integer.toString(index));
}
return value;
}
throw new UnsupportedOperationException();
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public boolean setArrayItem(JSONPath path, Object currentObject, int index, Object value) {
if (currentObject instanceof List) {
List list = (List) currentObject;
if (index >= 0) {
list.set(index, value);
} else {
list.set(list.size() + index, value);
}
return true;
}
Class<?> clazz = currentObject.getClass();
if (clazz.isArray()) {
int arrayLenth = Array.getLength(currentObject);
if (index >= 0) {
if (index < arrayLenth) {
Array.set(currentObject, index, value);
}
} else {
if (Math.abs(index) <= arrayLenth) {
Array.set(currentObject, arrayLenth + index, value);
}
}
return true;
}
throw new JSONPathException("unsupported set operation." + clazz);
}
@SuppressWarnings("rawtypes")
public boolean removeArrayItem(JSONPath path, Object currentObject, int index) {
if (currentObject instanceof List) {
List list = (List) currentObject;
if (index >= 0) {
if (index >= list.size()) {
return false;
}
list.remove(index);
} else {
int newIndex = list.size() + index;
if (newIndex < 0) {
return false;
}
list.remove(newIndex);
}
return true;
}
Class<?> clazz = currentObject.getClass();
throw new JSONPathException("unsupported set operation." + clazz);
}
@SuppressWarnings({ "rawtypes", "unchecked" })
protected Collection<Object> getPropertyValues(final Object currentObject) {
final Class<?> currentClass = currentObject.getClass();
JavaBeanSerializer beanSerializer = getJavaBeanSerializer(currentClass);
if (beanSerializer != null) {
try {
return beanSerializer.getFieldValues(currentObject);
} catch (Exception e) {
throw new JSONPathException("jsonpath error, path " + path, e);
}
}
if (currentObject instanceof Map) {
Map map = (Map) currentObject;
return map.values();
}
throw new UnsupportedOperationException();
}
static boolean eq(Object a, Object b) {
if (a == b) {
return true;
}
if (a == null || b == null) {
return false;
}
if (a.getClass() == b.getClass()) {
return a.equals(b);
}
if (a instanceof Number) {
if (b instanceof Number) {
return eqNotNull((Number) a, (Number) b);
}
return false;
}
return a.equals(b);
}
@SuppressWarnings("rawtypes")
static boolean eqNotNull(Number a, Number b) {
Class clazzA = a.getClass();
boolean isIntA = isInt(clazzA);
Class clazzB = b.getClass();
boolean isIntB = isInt(clazzB);
if (a instanceof BigDecimal) {
BigDecimal decimalA = (BigDecimal) a;
if (isIntB) {
return decimalA.equals(BigDecimal.valueOf(b.longValue()));
}
}
if (isIntA) {
if (isIntB) {
return a.longValue() == b.longValue();
}
if (b instanceof BigInteger) {
BigInteger bigIntB = (BigInteger) a;
BigInteger bigIntA = BigInteger.valueOf(a.longValue());
return bigIntA.equals(bigIntB);
}
}
if (isIntB) {
if (a instanceof BigInteger) {
BigInteger bigIntA = (BigInteger) a;
BigInteger bigIntB = BigInteger.valueOf(b.longValue());
return bigIntA.equals(bigIntB);
}
}
boolean isDoubleA = isDouble(clazzA);
boolean isDoubleB = isDouble(clazzB);
if ((isDoubleA && isDoubleB) || (isDoubleA && isIntB) || (isDoubleB && isIntA)) {
return a.doubleValue() == b.doubleValue();
}
return false;
}
protected static boolean isDouble(Class<?> clazzA) {
return clazzA == Float.class || clazzA == Double.class;
}
protected static boolean isInt(Class<?> clazzA) {
return clazzA == Byte.class || clazzA == Short.class || clazzA == Integer.class || clazzA == Long.class;
}
@SuppressWarnings("rawtypes")
protected Object getPropertyValue(final Object currentObject, final String propertyName, boolean strictMode) {
if (currentObject == null) {
return null;
}
if (currentObject instanceof Map) {
Map map = (Map) currentObject;
Object val = map.get(propertyName);
if (val == null && "size".equals(propertyName)) {
val = map.size();
}
return val;
}
final Class<?> currentClass = currentObject.getClass();
JavaBeanSerializer beanSerializer = getJavaBeanSerializer(currentClass);
if (beanSerializer != null) {
try {
return beanSerializer.getFieldValue(currentObject, propertyName);
} catch (Exception e) {
throw new JSONPathException("jsonpath error, path " + path + ", segement " + propertyName, e);
}
}
if (currentObject instanceof List) {
List list = (List) currentObject;
if ("size".equals(propertyName)) {
return list.size();
}
List<Object> fieldValues = new JSONArray(list.size());
for (int i = 0; i < list.size(); ++i) {
Object obj = list.get(i);
Object itemValue = getPropertyValue(obj, propertyName, strictMode);
if (itemValue instanceof Collection) {
Collection collection = (Collection) itemValue;
fieldValues.addAll(collection);
} else {
fieldValues.add(itemValue);
}
}
return fieldValues;
}
if (currentObject instanceof Enum) {
Enum e = (Enum) currentObject;
if ("name".equals(propertyName)) {
return e.name();
}
if ("ordinal".equals(propertyName)) {
return e.ordinal();
}
}
if (currentObject instanceof Calendar) {
Calendar e = (Calendar) currentObject;
if ("year".equals(propertyName)) {
return e.get(Calendar.YEAR);
}
if ("month".equals(propertyName)) {
return e.get(Calendar.MONTH);
}
if ("day".equals(propertyName)) {
return e.get(Calendar.DAY_OF_MONTH);
}
if ("hour".equals(propertyName)) {
return e.get(Calendar.HOUR_OF_DAY);
}
if ("minute".equals(propertyName)) {
return e.get(Calendar.MINUTE);
}
if ("second".equals(propertyName)) {
return e.get(Calendar.SECOND);
}
}
throw new JSONPathException("jsonpath error, path " + path + ", segement " + propertyName);
}
@SuppressWarnings("rawtypes")
protected void deepScan(final Object currentObject, final String propertyName, List<Object> results) {
if (currentObject == null) {
return;
}
if (currentObject instanceof Map) {
Map<?, ?> map = (Map<?, ?>) currentObject;
if (map.containsKey(propertyName)) {
Object val = map.get(propertyName);
results.add(val);
return;
}
for (Object val : map.values()) {
deepScan(val, propertyName, results);
}
return;
}
final Class<?> currentClass = currentObject.getClass();
JavaBeanSerializer beanSerializer = getJavaBeanSerializer(currentClass);
if (beanSerializer != null) {
try {
FieldSerializer fieldDeser = beanSerializer.getFieldSerializer(propertyName);
if (fieldDeser != null) {
try {
Object val = fieldDeser.getPropertyValueDirect(currentObject);
results.add(val);
} catch (InvocationTargetException ex) {
throw new JSONException("getFieldValue error." + propertyName, ex);
} catch (IllegalAccessException ex) {
throw new JSONException("getFieldValue error." + propertyName, ex);
}
return;
}
List<Object> fieldValues = beanSerializer.getFieldValues(currentObject);
for (Object val : fieldValues) {
deepScan(val, propertyName, results);
}
return;
} catch (Exception e) {
throw new JSONPathException("jsonpath error, path " + path + ", segement " + propertyName, e);
}
}
if (currentObject instanceof List) {
List list = (List) currentObject;
for (int i = 0; i < list.size(); ++i) {
Object val = list.get(i);
deepScan(val, propertyName, results);
}
return;
}
}
protected void deepSet(final Object currentObject, final String propertyName, Object value) {
if (currentObject == null) {
return;
}
if (currentObject instanceof Map) {
Map map = (Map) currentObject;
if (map.containsKey(propertyName)) {
Object val = map.get(propertyName);
map.put(propertyName, value);
return;
}
for (Object val : map.values()) {
deepSet(val, propertyName, value);
}
return;
}
final Class<?> currentClass = currentObject.getClass();
JavaBeanDeserializer beanDeserializer = getJavaBeanDeserializer(currentClass);
if (beanDeserializer != null) {
try {
FieldDeserializer fieldDeser = beanDeserializer.getFieldDeserializer(propertyName);
if (fieldDeser != null) {
fieldDeser.setValue(currentObject, value);
return;
}
JavaBeanSerializer beanSerializer = getJavaBeanSerializer(currentClass);
List<Object> fieldValues = beanSerializer.getObjectFieldValues(currentObject);
for (Object val : fieldValues) {
deepSet(val, propertyName, value);
}
return;
} catch (Exception e) {
throw new JSONPathException("jsonpath error, path " + path + ", segement " + propertyName, e);
}
}
if (currentObject instanceof List) {
List list = (List) currentObject;
for (int i = 0; i < list.size(); ++i) {
Object val = list.get(i);
deepSet(val, propertyName, value);
}
return;
}
}
@SuppressWarnings({ "unchecked", "rawtypes" })
protected boolean setPropertyValue(Object parent, String name, Object value) {
if (parent instanceof Map) {
((Map) parent).put(name, value);
return true;
}
if (parent instanceof List) {
for (Object element : (List) parent) {
if (element == null) {
continue;
}
setPropertyValue(element, name, value);
}
return true;
}
ObjectDeserializer derializer = parserConfig.getDeserializer(parent.getClass());
JavaBeanDeserializer beanDerializer = null;
if (derializer instanceof JavaBeanDeserializer) {
beanDerializer = (JavaBeanDeserializer) derializer;
}
if (beanDerializer != null) {
FieldDeserializer fieldDeserializer = beanDerializer.getFieldDeserializer(name);
if (fieldDeserializer == null) {
return false;
}
fieldDeserializer.setValue(parent, value);
return true;
}
throw new UnsupportedOperationException();
}
@SuppressWarnings({"rawtypes" })
protected boolean removePropertyValue(Object parent, String name) {
if (parent instanceof Map) {
Object origin = ((Map) parent).remove(name);
return origin != null;
}
ObjectDeserializer derializer = parserConfig.getDeserializer(parent.getClass());
JavaBeanDeserializer beanDerializer = null;
if (derializer instanceof JavaBeanDeserializer) {
beanDerializer = (JavaBeanDeserializer) derializer;
}
if (beanDerializer != null) {
FieldDeserializer fieldDeserializer = beanDerializer.getFieldDeserializer(name);
if (fieldDeserializer == null) {
return false;
}
fieldDeserializer.setValue(parent, null);
return true;
}
throw new UnsupportedOperationException();
}
protected JavaBeanSerializer getJavaBeanSerializer(final Class<?> currentClass) {
JavaBeanSerializer beanSerializer = null;
{
ObjectSerializer serializer = serializeConfig.getObjectWriter(currentClass);
if (serializer instanceof JavaBeanSerializer) {
beanSerializer = (JavaBeanSerializer) serializer;
}
}
return beanSerializer;
}
protected JavaBeanDeserializer getJavaBeanDeserializer(final Class<?> currentClass) {
JavaBeanDeserializer beanDeserializer = null;
{
ObjectDeserializer deserializer = parserConfig.getDeserializer(currentClass);
if (deserializer instanceof JavaBeanDeserializer) {
beanDeserializer = (JavaBeanDeserializer) deserializer;
}
}
return beanDeserializer;
}
@SuppressWarnings("rawtypes")
int evalSize(Object currentObject) {
if (currentObject == null) {
return -1;
}
if (currentObject instanceof Collection) {
return ((Collection) currentObject).size();
}
if (currentObject instanceof Object[]) {
return ((Object[]) currentObject).length;
}
if (currentObject.getClass().isArray()) {
return Array.getLength(currentObject);
}
if (currentObject instanceof Map) {
int count = 0;
for (Object value : ((Map) currentObject).values()) {
if (value != null) {
count++;
}
}
return count;
}
JavaBeanSerializer beanSerializer = getJavaBeanSerializer(currentObject.getClass());
if (beanSerializer == null) {
return -1;
}
try {
return beanSerializer.getSize(currentObject);
} catch (Exception e) {
throw new JSONPathException("evalSize error : " + path, e);
}
}
public String toJSONString() {
return JSON.toJSONString(path);
}
}