/src/main/java/com/alibaba/fastjson/JSONPath.java
https://github.com/alibaba/fastjson · Java · 1439 lines · 1132 code · 244 blank · 63 comment · 435 complexity · 090fccaaf9e371f8afa6e27e434c7eae MD5 · raw file
- package com.alibaba.fastjson;
- import com.alibaba.fastjson.parser.DefaultJSONParser;
- import com.alibaba.fastjson.parser.Feature;
- import com.alibaba.fastjson.parser.JSONLexer;
- import com.alibaba.fastjson.parser.JSONLexerBase;
- import com.alibaba.fastjson.parser.JSONToken;
- 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;
- import java.lang.reflect.Array;
- import java.lang.reflect.InvocationTargetException;
- import java.lang.reflect.Type;
- import java.math.BigDecimal;
- import java.math.BigInteger;
- import java.math.RoundingMode;
- import java.util.ArrayList;
- import java.util.Arrays;
- import java.util.Calendar;
- import java.util.Collection;
- import java.util.Collections;
- import java.util.Date;
- import java.util.HashMap;
- import java.util.IdentityHashMap;
- import java.util.Iterator;
- import java.util.List;
- import java.util.Map;
- import java.util.Set;
- import java.util.UUID;
- import java.util.concurrent.ConcurrentHashMap;
- import java.util.concurrent.ConcurrentMap;
- import java.util.regex.Matcher;
- import java.util.regex.Pattern;
- /**
- * @author wenshao[szujobs@hotmail.com]
- * @since 1.2.0
- */
- public class JSONPath implements JSONAware {
- private static ConcurrentMap<String, JSONPath> pathCache = new ConcurrentHashMap<String, JSONPath>(128, 0.75f, 1);
- private final String path;
- private Segment[] segments;
- private boolean hasRefSegment;
- private SerializeConfig serializeConfig;
- private ParserConfig parserConfig;
- private boolean ignoreNullValue;
- public JSONPath(String path){
- this(path, SerializeConfig.getGlobalInstance(), ParserConfig.getGlobalInstance(), true);
- }
- public JSONPath(String path, boolean ignoreNullValue){
- this(path, SerializeConfig.getGlobalInstance(), ParserConfig.getGlobalInstance(), ignoreNullValue);
- }
- public JSONPath(String path, SerializeConfig serializeConfig, ParserConfig parserConfig, boolean ignoreNullValue){
- 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;
- this.ignoreNullValue = ignoreNullValue;
- }
- protected void init() {
- if (segments != null) {
- return;
- }
- if ("*".equals(path)) {
- this.segments = new Segment[] { WildCardSegment.instance };
- } else {
- JSONPathParser parser = new JSONPathParser(path);
- this.segments = parser.explain();
- this.hasRefSegment = parser.hasRefSegment;
- }
- }
- public boolean isRef() {
- try {
- init();
- for (int i = 0; i < segments.length; ++i) {
- Segment segment = segments[i];
- Class segmentType = segment.getClass();
- if (segmentType == ArrayAccessSegment.class
- || segmentType == PropertySegment.class) {
- continue;
- }
- return false;
- }
- return true;
- } catch (JSONPathException ex) {
- // skip
- return false;
- }
- }
- public Object eval(Object rootObject) {
- if (rootObject == null) {
- return null;
- }
- init();
- Object currentObject = rootObject;
- for (int i = 0; i < segments.length; ++i) {
- Segment segment = segments[i];
- currentObject = segment.eval(this, rootObject, currentObject);
- }
- return currentObject;
- }
-
- /**
- * @since 1.2.76
- * @param rootObject
- * @param clazz
- * @param parserConfig
- * @return
- */
- public <T> T eval(Object rootObject, Type clazz, ParserConfig parserConfig) {
- Object obj = this.eval(rootObject);
- return TypeUtils.cast(obj, clazz, parserConfig);
- }
-
- /**
- * @since 1.2.76
- * @param rootObject
- * @param clazz
- * @return
- */
- public <T> T eval(Object rootObject, Type clazz) {
- return this.eval(rootObject, clazz, ParserConfig.getGlobalInstance());
- }
- public Object extract(DefaultJSONParser parser) {
- if (parser == null) {
- return null;
- }
- init();
- if (hasRefSegment) {
- Object root = parser.parse();
- return this.eval(root);
- }
- if (segments.length == 0) {
- return parser.parse();
- }
- Segment lastSegment = segments[segments.length - 1];
- if (lastSegment instanceof TypeSegment
- || lastSegment instanceof FloorSegment
- || lastSegment instanceof MultiIndexSegment) {
- return eval(
- parser.parse());
- }
- Context context = null;
- for (int i = 0; i < segments.length; ++i) {
- Segment segment = segments[i];
- boolean last = i == segments.length - 1;
- if (context != null && context.object != null) {
- context.object = segment.eval(this, null, context.object);
- continue;
- }
- boolean eval;
- if (!last) {
- Segment nextSegment = segments[i + 1];
- if (segment instanceof PropertySegment
- && ((PropertySegment) segment).deep
- && (nextSegment instanceof ArrayAccessSegment
- || nextSegment instanceof MultiIndexSegment
- || nextSegment instanceof MultiPropertySegment
- || nextSegment instanceof SizeSegment
- || nextSegment instanceof PropertySegment
- || nextSegment instanceof FilterSegment))
- {
- eval = true;
- } else if (nextSegment instanceof ArrayAccessSegment
- && ((ArrayAccessSegment) nextSegment).index < 0) {
- eval = true;
- } else if (nextSegment instanceof FilterSegment) {
- eval = true;
- } else if (segment instanceof WildCardSegment) {
- eval = true;
- }else if(segment instanceof MultiIndexSegment){
- eval = true;
- } else {
- eval = false;
- }
- } else {
- eval = true;
- }
- context = new Context(context, eval);
- segment.extract(this, parser, context);
- }
- return context.object;
- }
- private static class Context {
- final Context parent;
- final boolean eval;
- Object object;
- public Context(Context parent, boolean eval) {
- this.parent = parent;
- this.eval = eval;
- }
- }
- public boolean contains(Object rootObject) {
- if (rootObject == null) {
- return false;
- }
- init();
- Object currentObject = rootObject;
- for (int i = 0; i < segments.length; ++i) {
- Object parentObject = currentObject;
- currentObject = segments[i].eval(this, rootObject, currentObject);
- if (currentObject == null) {
- return false;
- }
- if (currentObject == Collections.EMPTY_LIST && parentObject instanceof List) {
- return ((List) parentObject).contains(currentObject);
- }
- }
- 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);
- }
- /**
- * Extract keySet or field names from rootObject on this JSONPath.
- *
- * @param rootObject Can be a map or custom object. Array and Collection are not supported.
- * @return Set of keys, or <code>null</code> if not supported.
- */
- public Set<?> keySet(Object rootObject) {
- if (rootObject == null) {
- return null;
- }
- init();
- Object currentObject = rootObject;
- for (int i = 0; i < segments.length; ++i) {
- currentObject = segments[i].eval(this, rootObject, currentObject);
- }
- return evalKeySet(currentObject);
- }
- public void patchAdd(Object rootObject, Object value, boolean replace) {
- if (rootObject == null) {
- return;
- }
- init();
- Object currentObject = rootObject;
- Object parentObject = null;
- for (int i = 0; i < segments.length; ++i) {
- parentObject = currentObject;
- Segment segment = segments[i];
- currentObject = segment.eval(this, rootObject, currentObject);
- if (currentObject == null && i != segments.length - 1) {
- if (segment instanceof PropertySegment) {
- currentObject = new JSONObject();
- ((PropertySegment) segment).setValue(this, parentObject, currentObject);
- }
- }
- }
- Object result = currentObject;
- if ((!replace) && result instanceof Collection) {
- Collection collection = (Collection) result;
- collection.add(value);
- return;
- }
- Object newResult;
- if (result != null && !replace) {
- Class<?> resultClass = result.getClass();
- if (resultClass.isArray()) {
- int length = Array.getLength(result);
- Object descArray = Array.newInstance(resultClass.getComponentType(), length + 1);
- System.arraycopy(result, 0, descArray, 0, length);
- Array.set(descArray, length, value);
- newResult = descArray;
- }
- else if (Map.class.isAssignableFrom(resultClass)) {
- newResult = value;
- } else {
- throw new JSONException("unsupported array put operation. " + resultClass);
- }
- } else {
- newResult = value;
- }
- Segment lastSegment = segments[segments.length - 1];
- if (lastSegment instanceof PropertySegment) {
- PropertySegment propertySegment = (PropertySegment) lastSegment;
- propertySegment.setValue(this, parentObject, newResult);
- return;
- }
- if (lastSegment instanceof ArrayAccessSegment) {
- ((ArrayAccessSegment) lastSegment).setValue(this, parentObject, newResult);
- return;
- }
- throw new UnsupportedOperationException();
- }
- @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);
- }
- Segment lastSegment = segments[segments.length - 1];
- if (lastSegment instanceof PropertySegment) {
- PropertySegment propertySegment = (PropertySegment) lastSegment;
- propertySegment.setValue(this, parentObject, newResult);
- return;
- }
- if (lastSegment instanceof ArrayAccessSegment) {
- ((ArrayAccessSegment) lastSegment).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;
- Segment lastSegment = segments[segments.length - 1];
- for (int i = 0; i < segments.length; ++i) {
- if (i == segments.length - 1) {
- parentObject = currentObject;
- break;
- }
- Segment segement = segments[i];
- if (i == segments.length - 2
- && lastSegment instanceof FilterSegment
- && segement instanceof PropertySegment
- ) {
- FilterSegment filterSegment = (FilterSegment) lastSegment;
- if (currentObject instanceof List) {
- PropertySegment propertySegment = (PropertySegment) segement;
- List list = (List) currentObject;
- for (Iterator it = list.iterator();it.hasNext();) {
- Object item = it.next();
- Object result = propertySegment.eval(this, rootObject, item);
- if (result instanceof Iterable) {
- filterSegment.remove(this, rootObject, result);
- } else if (result instanceof Map) {
- if (filterSegment.filter.apply(this, rootObject, currentObject, result)) {
- it.remove();
- }
- }
- }
- return true;
- } else if (currentObject instanceof Map) {
- PropertySegment propertySegment = (PropertySegment) segement;
- Object result = propertySegment.eval(this, rootObject, currentObject);
- if (result == null) {
- return false;
- }
- if (result instanceof Map
- && filterSegment.filter.apply(this, rootObject, currentObject, result)) {
- propertySegment.remove(this, currentObject);
- return true;
- }
- }
- }
- currentObject = segement.eval(this, rootObject, currentObject);
- if (currentObject == null) {
- break;
- }
- }
- if (parentObject == null) {
- return false;
- }
- if (lastSegment instanceof PropertySegment) {
- PropertySegment propertySegment = (PropertySegment) lastSegment;
- if (parentObject instanceof Collection) {
- if (segments.length > 1) {
- Segment parentSegment = segments[segments.length - 2];
- if (parentSegment instanceof RangeSegment || parentSegment instanceof MultiIndexSegment) {
- Collection collection = (Collection) parentObject;
- boolean removedOnce = false;
- for (Object item : collection) {
- boolean removed = propertySegment.remove(this, item);
- if (removed) {
- removedOnce = true;
- }
- }
- return removedOnce;
- }
- }
- }
- return propertySegment.remove(this, parentObject);
- }
- if (lastSegment instanceof ArrayAccessSegment) {
- return ((ArrayAccessSegment) lastSegment).remove(this, parentObject);
- }
- if (lastSegment instanceof FilterSegment) {
- FilterSegment filterSegment = (FilterSegment) lastSegment;
- return filterSegment.remove(this, rootObject, 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;
- Segment segment = segments[i];
- currentObject = segment.eval(this, rootObject, currentObject);
- if (currentObject == null) {
- Segment nextSegment = null;
- if (i < segments.length - 1) {
- nextSegment = segments[i + 1];
- }
- Object newObj = null;
- if (nextSegment instanceof PropertySegment) {
- JavaBeanDeserializer beanDeserializer = null;
- Class<?> fieldClass = null;
- if (segment instanceof PropertySegment) {
- String propertyName = ((PropertySegment) 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 (nextSegment instanceof ArrayAccessSegment) {
- newObj = new JSONArray();
- }
-
- if (newObj != null) {
- if (segment instanceof PropertySegment) {
- PropertySegment propSegement = (PropertySegment) segment;
- propSegement.setValue(this, parentObject, newObj);
- currentObject = newObj;
- continue;
- } else if (segment instanceof ArrayAccessSegment) {
- ArrayAccessSegment arrayAccessSegement = (ArrayAccessSegment) segment;
- arrayAccessSegement.setValue(this, parentObject, newObj);
- currentObject = newObj;
- continue;
- }
- }
-
- break;
- }
- }
- if (parentObject == null) {
- return false;
- }
- Segment lastSegment = segments[segments.length - 1];
- if (lastSegment instanceof PropertySegment) {
- PropertySegment propertySegment = (PropertySegment) lastSegment;
- propertySegment.setValue(this, parentObject, value);
- return true;
- }
- if (lastSegment instanceof ArrayAccessSegment) {
- return ((ArrayAccessSegment) lastSegment).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 Object eval(Object rootObject, String path, boolean ignoreNullValue) {
- JSONPath jsonpath = compile(path, ignoreNullValue);
- 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);
- }
- /**
- * Compile jsonPath and use it to extract keySet or field names from rootObject.
- *
- * @param rootObject Can be a map or custom object. Array and Collection are not supported.
- * @param path JSONPath string to be compiled.
- * @return Set of keys, or <code>null</code> if not supported.
- */
- public static Set<?> keySet(Object rootObject, String path) {
- JSONPath jsonpath = compile(path);
- Object result = jsonpath.eval(rootObject);
- return jsonpath.evalKeySet(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() < 1024) {
- pathCache.putIfAbsent(path, jsonpath);
- jsonpath = pathCache.get(path);
- }
- }
- return jsonpath;
- }
- public static JSONPath compile(String path, boolean ignoreNullValue) {
- if (path == null) {
- throw new JSONPathException("jsonpath can not be null");
- }
- JSONPath jsonpath = pathCache.get(path);
- if (jsonpath == null) {
- jsonpath = new JSONPath(path, ignoreNullValue);
- if (pathCache.size() < 1024) {
- 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) {
- return compile(path)
- .eval(
- JSON.parse(json)
- );
- }
-
- /**
- * @since 1.2.76
- * @param json
- * @param path
- * @param clazz
- * @param parserConfig
- * @return
- */
- public static <T> T read(String json, String path, Type clazz, ParserConfig parserConfig) {
- return compile(path).eval(JSON.parse(json), clazz, parserConfig);
- }
-
- /**
- * @since 1.2.76
- * @param json
- * @param path
- * @param clazz
- * @return
- */
- public static <T> T read(String json, String path, Type clazz) {
- return read(json, path, clazz, null);
- }
- /**
- * @since 1.2.51
- * @param json
- * @param path
- * @return
- */
- public static Object extract(String json, String path, ParserConfig config, int features, Feature... optionFeatures) {
- features |= Feature.OrderedField.mask;
- DefaultJSONParser parser = new DefaultJSONParser(json, config, features);
- JSONPath jsonPath = compile(path);
- Object result = jsonPath.extract(parser);
- parser.lexer.close();
- return result;
- }
- public static Object extract(String json, String path) {
- return extract(json, path, ParserConfig.global, JSON.DEFAULT_PARSER_FEATURE);
- }
- 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>();
- Map<String, Object> paths = new HashMap<String, Object>();
- paths(values, paths, "/", javaObject, config);
- return paths;
- }
- private static void paths(Map<Object, String> values, Map<String, Object> paths, String parent, Object javaObject, SerializeConfig config) {
- if (javaObject == null) {
- return;
- }
- String p = values.put(javaObject, parent);
- if (p != null) {
- Class<?> type = javaObject.getClass();
- boolean basicType = type == String.class
- || type == Boolean.class
- || type == Character.class
- || type == UUID.class
- || type.isEnum()
- || javaObject instanceof Number
- || javaObject instanceof Date
- ;
- if (!basicType) {
- return;
- }
- }
- paths.put(parent, javaObject);
- 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(values, 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(values, 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(values, 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(values, 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;
- private boolean hasRefSegment;
- private static final String strArrayRegex = "\'\\s*,\\s*\'";
- private static final Pattern strArrayPatternx = Pattern.compile(strArrayRegex);
- public JSONPathParser(String path){
- this.path = path;
- next();
- }
- void next() {
- ch = path.charAt(pos++);
- }
- char getNextChar() {
- return path.charAt(pos);
- }
- boolean isEOF() {
- return pos >= path.length();
- }
- Segment readSegement() {
- if (level == 0 && path.length() == 1) {
- if (isDigitFirst(ch)) {
- int index = ch - '0';
- return new ArrayAccessSegment(index);
- } else if ((ch >= 'a' && ch <= 'z') || ((ch >= 'A' && ch <= 'Z'))) {
- return new PropertySegment(Character.toString(ch), false);
- }
- }
- while (!isEOF()) {
- skipWhitespace();
- if (ch == '$') {
- next();
- skipWhitespace();
- if (ch == '?') {
- return new FilterSegment(
- (Filter) parseArrayAccessFilter(false));
- }
- continue;
- }
- if (ch == '.' || ch == '/') {
- int c0 = ch;
- boolean deep = false;
- next();
- if (c0 == '.' && ch == '.') {
- next();
- deep = true;
- if (path.length() > pos + 3
- && ch == '['
- && path.charAt(pos) == '*'
- && path.charAt(pos + 1) == ']'
- && path.charAt(pos + 2) == '.') {
- next();
- next();
- next();
- next();
- }
- }
- if (ch == '*' || (deep && ch == '[')) {
- boolean objectOnly = ch == '[';
- if (!isEOF()) {
- next();
- }
- if (deep) {
- if (objectOnly) {
- return WildCardSegment.instance_deep_objectOnly;
- } else {
- return WildCardSegment.instance_deep;
- }
- } else {
- return WildCardSegment.instance;
- }
- }
-
- if (isDigitFirst(ch)) {
- return parseArrayAccess(false);
- }
- String propertyName = readName();
- if (ch == '(') {
- next();
- if (ch == ')') {
- if (!isEOF()) {
- next();
- }
- if ("size".equals(propertyName) || "length".equals(propertyName)) {
- return SizeSegment.instance;
- } else if ("max".equals(propertyName)) {
- return MaxSegment.instance;
- } else if ("min".equals(propertyName)) {
- return MinSegment.instance;
- } else if ("keySet".equals(propertyName)) {
- return KeySetSegment.instance;
- } else if ("type".equals(propertyName)) {
- return TypeSegment.instance;
- } else if ("floor".equals(propertyName)) {
- return FloorSegment.instance;
- }
- throw new JSONPathException("not support jsonpath : " + path);
- }
- throw new JSONPathException("not support jsonpath : " + path);
- }
- return new PropertySegment(propertyName, deep);
- }
- if (ch == '[') {
- return parseArrayAccess(true);
- }
- if (level == 0) {
- String propertyName = readName();
- return new PropertySegment(propertyName, false);
- }
- if (ch == '?') {
- return new FilterSegment(
- (Filter) parseArrayAccessFilter(false));
- }
- throw new JSONPathException("not support jsonpath : " + path);
- }
- return null;
- }
- public final void skipWhitespace() {
- for (;;) {
- if (ch <= ' ' && (ch == ' ' || ch == '\r' || ch == '\n' || ch == '\t' || ch == '\f' || ch == '\b')) {
- next();
- continue;
- } else {
- break;
- }
- }
- }
- Segment parseArrayAccess(boolean acceptBracket) {
- Object object = parseArrayAccessFilter(acceptBracket);
- if (object instanceof Segment) {
- return ((Segment) object);
- }
- return new FilterSegment((Filter) object);
- }
- Object parseArrayAccessFilter(boolean acceptBracket) {
- if (acceptBracket) {
- accept('[');
- }
- boolean predicateFlag = false;
- int lparanCount = 0;
- if (ch == '?') {
- next();
- accept('(');
- lparanCount++;
- while (ch == '(') {
- next();
- lparanCount++;
- }
- predicateFlag = true;
- }
- skipWhitespace();
- if (predicateFlag
- || IOUtils.firstIdentifier(ch)
- || Character.isJavaIdentifierStart(ch)
- || ch == '\\'
- || ch == '@') {
- boolean self = false;
- if (ch == '@') {
- next();
- accept('.');
- self = true;
- }
- String propertyName = readName();
- skipWhitespace();
- if (predicateFlag && ch == ')') {
- next();
- Filter filter = new NotNullSegement(propertyName, false);
- while (ch == ' ') {
- next();
- }
- if (ch == '&' || ch == '|') {
- filter = filterRest(filter);
- }
- if (acceptBracket) {
- accept(']');
- }
- return filter;
- }
- if (acceptBracket && ch == ']') {
- if (isEOF()) {
- if (propertyName.equals("last")) {
- return new MultiIndexSegment(new int[]{-1});
- }
- }
- next();
- Filter filter = new NotNullSegement(propertyName, false);
- while (ch == ' ') {
- next();
- }
- if (ch == '&' || ch == '|') {
- filter = filterRest(filter);
- }
- accept(')');
- if (predicateFlag) {
- accept(')');
- }
- if (acceptBracket) {
- accept(']');
- }
- return filter;
- }
- boolean function = false;
- skipWhitespace();
- if (ch == '(') {
- next();
- accept(')');
- skipWhitespace();
- function = true;
- }
- 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
- , function
- , TypeUtils.longExtractValue((Number) startValue)
- , TypeUtils.longExtractValue((Number) endValue)
- , not);
- return 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);
- }
- }
- 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) {
- Filter filter;
- if (not) {
- filter = new NotNullSegement(propertyName, function);
- } else {
- filter = new NullSegement(propertyName, function);
- }
- while (ch == ' ') {
- next();
- }
- if (ch == '&' || ch == '|') {
- filter = filterRest(filter);
- }
- accept(')');
- if (predicateFlag) {
- accept(')');
- }
- if (acceptBracket) {
- accept(']');
- }
- return filter;
- }
- if (isInt) {
- if (valueList.size() == 1) {
- long value = TypeUtils.longExtractValue((Number) valueList.get(0));
- Operator intOp = not ? Operator.NE : Operator.EQ;
- Filter filter = new IntOpSegement(propertyName, function, value, intOp);
- while (ch == ' ') {
- next();
- }
- if (ch == '&' || ch == '|') {
- filter = filterRest(filter);
- }
- accept(')');
- if (predicateFlag) {
- accept(')');
- }
- if (acceptBracket) {
- accept(']');
- }
- return filter;
- }
- long[] values = new long[valueList.size()];
- for (int i = 0; i < values.length; ++i) {
- values[i] = TypeUtils.longExtractValue((Number) valueList.get(i));
- }
- Filter filter = new IntInSegement(propertyName, function, values, not);
- while (ch == ' ') {
- next();
- }
- if (ch == '&' || ch == '|') {
- filter = filterRest(filter);
- }
- accept(')');
- if (predicateFlag) {
- accept(')');
- }
- if (acceptBracket) {
- accept(']');
- }
- return filter;
- }
- if (isString) {
- if (valueList.size() == 1) {
- String value = (String) valueList.get(0);
- Operator intOp = not ? Operator.NE : Operator.EQ;
- Filter filter = new StringOpSegement(propertyName, function, value, intOp);
- while (ch == ' ') {
- next();
- }
- if (ch == '&' || ch == '|') {
- filter = filterRest(filter);
- }
- accept(')');
- if (predicateFlag) {
- accept(')');
- }
- if (acceptBracket) {
- accept(']');
- }
- return filter;
- }
- String[] values = new String[valueList.size()];
- valueList.toArray(values);
- Filter filter = new StringInSegement(propertyName, function, values, not);
- while (ch == ' ') {
- next();
- }
- if (ch == '&' || ch == '|') {
- filter = filterRest(filter);
- }
- accept(')');
- if (predicateFlag) {
- accept(')');
- }
- if (acceptBracket) {
- accept(']');
- }
- return filter;
- }
- 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] = TypeUtils.longExtractValue(item);
- }
- }
- Filter filter = new IntObjInSegement(propertyName, function, values, not);
- while (ch == ' ') {
- next();
- }
- if (ch == '&' || ch == '|') {
- filter = filterRest(filter);
- }
- accept(')');
- if (predicateFlag) {
- accept(')');
- }
- if (acceptBracket) {
- accept(']');
- }
- return filter;
- }
- throw new UnsupportedOperationException();
- }
- if (ch == '\'' || ch == '"') {
- String strValue = readString();
- Filter filter = null;
- if (op == Operator.RLIKE) {
- filter = new RlikeSegement(propertyName, function, strValue, false);
- } else if (op == Operator.NOT_RLIKE) {
- filter = new RlikeSegement(propertyName, function, strValue, true);
- } else 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;
- }
- filter = new StringOpSegement(propertyName, function, strValue, op);
- } 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) == '%') {
- if (items.length == 1) {
- startsWithValue = items[0];
- } else {
- containsValues = items;
- }
- } else {
- if (items.length == 1) {
- startsWithValue = items[0];
- } else if (items.length == 2) {
- startsWithValue = items[0];