Browse Source

Merge pull request #416 from genman/quote-fix

Quote fix & code clean up
pull/517/head
kallestenflo 6 years ago committed by GitHub
parent
commit
78c04fc48f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 16
      json-path/src/main/java/com/jayway/jsonpath/Criteria.java
  2. 11
      json-path/src/main/java/com/jayway/jsonpath/internal/CharacterIndex.java
  3. 2
      json-path/src/main/java/com/jayway/jsonpath/internal/DefaultsImpl.java
  4. 2
      json-path/src/main/java/com/jayway/jsonpath/internal/PathRef.java
  5. 8
      json-path/src/main/java/com/jayway/jsonpath/internal/Utils.java
  6. 13
      json-path/src/main/java/com/jayway/jsonpath/internal/filter/EvaluatorFactory.java
  7. 33
      json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java
  8. 652
      json-path/src/main/java/com/jayway/jsonpath/internal/filter/ValueNode.java
  9. 662
      json-path/src/main/java/com/jayway/jsonpath/internal/filter/ValueNodes.java
  10. 2
      json-path/src/main/java/com/jayway/jsonpath/internal/function/text/Concatenate.java
  11. 52
      json-path/src/main/java/com/jayway/jsonpath/internal/path/ArrayIndexToken.java
  12. 138
      json-path/src/main/java/com/jayway/jsonpath/internal/path/ArrayPathToken.java
  13. 18
      json-path/src/main/java/com/jayway/jsonpath/internal/path/ArraySliceOperation.java
  14. 114
      json-path/src/main/java/com/jayway/jsonpath/internal/path/ArraySliceToken.java
  15. 2
      json-path/src/main/java/com/jayway/jsonpath/internal/path/CompiledPath.java
  16. 4
      json-path/src/main/java/com/jayway/jsonpath/internal/path/PathCompiler.java
  17. 4
      json-path/src/main/java/com/jayway/jsonpath/internal/path/PathTokenFactory.java
  18. 3
      json-path/src/main/java/com/jayway/jsonpath/internal/path/PredicatePathToken.java
  19. 2
      json-path/src/main/java/com/jayway/jsonpath/internal/path/RootPathToken.java
  20. 4
      json-path/src/main/java/com/jayway/jsonpath/internal/path/WildcardPathToken.java
  21. 4
      json-path/src/main/java/com/jayway/jsonpath/spi/cache/CacheProvider.java
  22. 2
      json-path/src/main/java/com/jayway/jsonpath/spi/json/AbstractJsonProvider.java
  23. 3
      json-path/src/test/java/com/jayway/jsonpath/FilterTest.java
  24. 3
      json-path/src/test/java/com/jayway/jsonpath/MultiPropTest.java
  25. 24
      json-path/src/test/java/com/jayway/jsonpath/OptionsTest.java
  26. 44
      json-path/src/test/java/com/jayway/jsonpath/PathCompilerTest.java
  27. 8
      json-path/src/test/java/com/jayway/jsonpath/ReturnTypeTest.java
  28. 14
      json-path/src/test/java/com/jayway/jsonpath/old/IssuesTest.java
  29. 2
      json-path/src/test/java/com/jayway/jsonpath/old/JsonPathTest.java

16
json-path/src/main/java/com/jayway/jsonpath/Criteria.java

@ -28,7 +28,9 @@ import java.util.List;
import java.util.regex.Pattern;
import static com.jayway.jsonpath.internal.Utils.notNull;
import com.jayway.jsonpath.internal.filter.ValueNodes;
import static com.jayway.jsonpath.internal.filter.ValueNodes.ValueListNode;
import static com.jayway.jsonpath.internal.filter.ValueNodes.PredicateNode;
/**
*
@ -225,7 +227,7 @@ public class Criteria implements Predicate {
public Criteria in(Collection<?> c) {
notNull(c, "collection can not be null");
this.criteriaType = RelationalOperator.IN;
this.right = new ValueNode.ValueListNode(c);
this.right = new ValueListNode(c);
return this;
}
@ -263,7 +265,7 @@ public class Criteria implements Predicate {
public Criteria nin(Collection<?> c) {
notNull(c, "collection can not be null");
this.criteriaType = RelationalOperator.NIN;
this.right = new ValueNode.ValueListNode(c);
this.right = new ValueListNode(c);
return this;
}
@ -290,7 +292,7 @@ public class Criteria implements Predicate {
public Criteria subsetof(Collection<?> c) {
notNull(c, "collection can not be null");
this.criteriaType = RelationalOperator.SUBSETOF;
this.right = new ValueNode.ValueListNode(c);
this.right = new ValueListNode(c);
return this;
}
@ -315,7 +317,7 @@ public class Criteria implements Predicate {
public Criteria all(Collection<?> c) {
notNull(c, "collection can not be null");
this.criteriaType = RelationalOperator.ALL;
this.right = new ValueNode.ValueListNode(c);
this.right = new ValueListNode(c);
return this;
}
@ -389,7 +391,7 @@ public class Criteria implements Predicate {
*/
public Criteria empty(boolean empty) {
this.criteriaType = RelationalOperator.EMPTY;
this.right = empty ? ValueNode.TRUE : ValueNode.FALSE;
this.right = empty ? ValueNodes.TRUE : ValueNodes.FALSE;
return this;
}
@ -401,7 +403,7 @@ public class Criteria implements Predicate {
*/
public Criteria matches(Predicate p) {
this.criteriaType = RelationalOperator.MATCHES;
this.right = new ValueNode.PredicateNode(p);
this.right = new PredicateNode(p);
return this;
}

11
json-path/src/main/java/com/jayway/jsonpath/internal/CharacterIndex.java

@ -172,7 +172,7 @@ public class CharacterIndex {
inEscape = false;
} else if('\\' == charAt(readPosition)){
inEscape = true;
} else if (c == charAt(readPosition) && !inEscape){
} else if (c == charAt(readPosition)){
return readPosition;
}
readPosition ++;
@ -220,16 +220,17 @@ public class CharacterIndex {
incrementPosition(1);
}
public void readSignificantSubSequence(CharSequence s) {
public boolean hasSignificantSubSequence(CharSequence s) {
skipBlanks();
if (! inBounds(position + s.length() - 1)) {
throw new InvalidPathException(String.format("End of string reached while expecting: %s", s));
return false;
}
if (! subSequence(position, position + s.length()).equals(s)) {
throw new InvalidPathException(String.format("Expected: %s", s));
return false;
}
incrementPosition(s.length());
return true;
}
public int indexOfPreviousSignificantChar(int startPosition){
@ -314,4 +315,4 @@ public class CharacterIndex {
skipBlanksAtEnd();
return this;
}
}
}

2
json-path/src/main/java/com/jayway/jsonpath/internal/DefaultsImpl.java

@ -32,6 +32,6 @@ public final class DefaultsImpl implements Defaults {
}
private DefaultsImpl() {
};
}
}

2
json-path/src/main/java/com/jayway/jsonpath/internal/PathRef.java

@ -212,7 +212,7 @@ public abstract class PathRef implements Comparable<PathRef> {
public int compareTo(PathRef o) {
if(o instanceof ArrayIndexPathRef){
ArrayIndexPathRef pf = (ArrayIndexPathRef) o;
return Integer.valueOf(pf.index).compareTo(this.index);
return Integer.compare(pf.index, this.index);
}
return super.compareTo(o);
}

8
json-path/src/main/java/com/jayway/jsonpath/internal/Utils.java

@ -24,8 +24,8 @@ import java.util.Iterator;
public final class Utils {
// accept a collection of objects, since all objects have toString()
public static String join(String delimiter, String wrap, Iterable<? extends Object> objs) {
Iterator<? extends Object> iter = objs.iterator();
public static String join(String delimiter, String wrap, Iterable<?> objs) {
Iterator<?> iter = objs.iterator();
if (!iter.hasNext()) {
return "";
}
@ -38,7 +38,7 @@ public final class Utils {
}
// accept a collection of objects, since all objects have toString()
public static String join(String delimiter, Iterable<? extends Object> objs) {
public static String join(String delimiter, Iterable<?> objs) {
return join(delimiter, "", objs);
}
@ -175,7 +175,7 @@ public final class Utils {
}
int len = str.length();
StringWriter writer = new StringWriter(len);
StringBuffer unicode = new StringBuffer(4);
StringBuilder unicode = new StringBuilder(4);
boolean hadSlash = false;
boolean inUnicode = false;
for (int i = 0; i < len; i++) {

13
json-path/src/main/java/com/jayway/jsonpath/internal/filter/EvaluatorFactory.java

@ -2,6 +2,7 @@ package com.jayway.jsonpath.internal.filter;
import com.jayway.jsonpath.JsonPathException;
import com.jayway.jsonpath.Predicate;
import static com.jayway.jsonpath.internal.filter.ValueNodes.*;
import java.util.HashMap;
import java.util.Map;
@ -168,7 +169,7 @@ public class EvaluatorFactory {
private static class InEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
ValueNode.ValueListNode valueListNode;
ValueListNode valueListNode;
if(right.isJsonNode()){
ValueNode vn = right.asJsonNode().asValueListNode(ctx);
if(vn.isUndefinedNode()){
@ -193,12 +194,12 @@ public class EvaluatorFactory {
private static class AllEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
ValueNode.ValueListNode requiredValues = right.asValueListNode();
ValueListNode requiredValues = right.asValueListNode();
if(left.isJsonNode()){
ValueNode valueNode = left.asJsonNode().asValueListNode(ctx); //returns UndefinedNode if conversion is not possible
if(valueNode.isValueListNode()){
ValueNode.ValueListNode shouldContainAll = valueNode.asValueListNode();
ValueListNode shouldContainAll = valueNode.asValueListNode();
for (ValueNode required : requiredValues) {
if(!shouldContainAll.contains(required)){
return false;
@ -249,7 +250,7 @@ public class EvaluatorFactory {
}
}
private boolean matches(ValueNode.PatternNode patternNode, String inputToMatch) {
private boolean matches(PatternNode patternNode, String inputToMatch) {
return patternNode.getCompiledPattern().matcher(inputToMatch).matches();
}
@ -269,7 +270,7 @@ public class EvaluatorFactory {
private static class SubsetOfEvaluator implements Evaluator {
@Override
public boolean evaluate(ValueNode left, ValueNode right, Predicate.PredicateContext ctx) {
ValueNode.ValueListNode rightValueListNode;
ValueListNode rightValueListNode;
if(right.isJsonNode()){
ValueNode vn = right.asJsonNode().asValueListNode(ctx);
if(vn.isUndefinedNode()){
@ -280,7 +281,7 @@ public class EvaluatorFactory {
} else {
rightValueListNode = right.asValueListNode();
}
ValueNode.ValueListNode leftValueListNode;
ValueListNode leftValueListNode;
if(left.isJsonNode()){
ValueNode vn = left.asJsonNode().asValueListNode(ctx);
if(vn.isUndefinedNode()){

33
json-path/src/main/java/com/jayway/jsonpath/internal/filter/FilterCompiler.java

@ -4,13 +4,14 @@ import com.jayway.jsonpath.Filter;
import com.jayway.jsonpath.InvalidPathException;
import com.jayway.jsonpath.Predicate;
import com.jayway.jsonpath.internal.CharacterIndex;
import static com.jayway.jsonpath.internal.filter.ValueNodes.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
public class FilterCompiler {
public class FilterCompiler {
private static final Logger logger = LoggerFactory.getLogger(FilterCompiler.class);
private static final char DOC_CONTEXT = '$';
@ -132,11 +133,9 @@ public class FilterCompiler {
while (true) {
int savepoint = filter.position();
try {
filter.readSignificantSubSequence(LogicalOperator.OR.getOperatorString());
if (filter.hasSignificantSubSequence(LogicalOperator.OR.getOperatorString())) {
ops.add(readLogicalAND());
}
catch (InvalidPathException exc) {
} else {
filter.setPosition(savepoint);
break;
}
@ -152,11 +151,9 @@ public class FilterCompiler {
while (true) {
int savepoint = filter.position();
try {
filter.readSignificantSubSequence(LogicalOperator.AND.getOperatorString());
if (filter.hasSignificantSubSequence(LogicalOperator.AND.getOperatorString())) {
ops.add(readLogicalANDOperand());
}
catch (InvalidPathException exc) {
} else {
filter.setPosition(savepoint);
break;
}
@ -201,10 +198,10 @@ public class FilterCompiler {
filter.setPosition(savepoint);
}
ValueNode.PathNode pathNode = left.asPathNode();
PathNode pathNode = left.asPathNode();
left = pathNode.asExistsCheck(pathNode.shouldExists());
RelationalOperator operator = RelationalOperator.EXISTS;
ValueNode right = left.asPathNode().shouldExists() ? ValueNode.TRUE : ValueNode.FALSE;
ValueNode right = left.asPathNode().shouldExists() ? ValueNodes.TRUE : ValueNodes.FALSE;
return new RelationalExpressionNode(left, operator, right);
}
@ -243,7 +240,7 @@ public class FilterCompiler {
return RelationalOperator.fromString(operator.toString());
}
private ValueNode.NullNode readNullLiteral() {
private NullNode readNullLiteral() {
int begin = filter.position();
if(filter.currentChar() == NULL && filter.inBounds(filter.position() + 3)){
CharSequence nullValue = filter.subSequence(filter.position(), filter.position() + 4);
@ -256,7 +253,7 @@ public class FilterCompiler {
throw new InvalidPathException("Expected <null> value");
}
private ValueNode.JsonNode readJsonLiteral(){
private JsonNode readJsonLiteral(){
int begin = filter.position();
char openChar = filter.currentChar();
@ -277,7 +274,7 @@ public class FilterCompiler {
}
private ValueNode.PatternNode readPattern() {
private PatternNode readPattern() {
int begin = filter.position();
int closingIndex = filter.nextIndexOfUnescaped(PATTERN);
if (closingIndex == -1) {
@ -293,7 +290,7 @@ public class FilterCompiler {
return ValueNode.createPatternNode(pattern);
}
private ValueNode.StringNode readStringLiteral(char endChar) {
private StringNode readStringLiteral(char endChar) {
int begin = filter.position();
int closingSingleQuoteIndex = filter.nextIndexOfUnescaped(endChar);
@ -307,7 +304,7 @@ public class FilterCompiler {
return ValueNode.createStringNode(stringLiteral, true);
}
private ValueNode.NumberNode readNumberLiteral() {
private NumberNode readNumberLiteral() {
int begin = filter.position();
while (filter.inBounds() && filter.isNumberCharacter(filter.position())) {
@ -318,7 +315,7 @@ public class FilterCompiler {
return ValueNode.createNumberNode(numberLiteral);
}
private ValueNode.BooleanNode readBooleanLiteral() {
private BooleanNode readBooleanLiteral() {
int begin = filter.position();
int end = filter.currentChar() == TRUE ? filter.position() + 3 : filter.position() + 4;
@ -335,7 +332,7 @@ public class FilterCompiler {
return ValueNode.createBooleanNode(boolValue);
}
private ValueNode.PathNode readPath() {
private PathNode readPath() {
char previousSignificantChar = filter.previousSignificantChar();
int begin = filter.position();

652
json-path/src/main/java/com/jayway/jsonpath/internal/filter/ValueNode.java

@ -1,40 +1,17 @@
package com.jayway.jsonpath.internal.filter;
import com.jayway.jsonpath.Configuration;
import java.util.regex.Pattern;
import com.jayway.jsonpath.InvalidPathException;
import com.jayway.jsonpath.JsonPathException;
import com.jayway.jsonpath.Option;
import com.jayway.jsonpath.PathNotFoundException;
import com.jayway.jsonpath.Predicate;
import com.jayway.jsonpath.internal.Path;
import com.jayway.jsonpath.internal.Utils;
import com.jayway.jsonpath.internal.path.PathCompiler;
import com.jayway.jsonpath.internal.path.PredicateContextImpl;
import com.jayway.jsonpath.spi.json.JsonProvider;
import net.minidev.json.parser.JSONParser;
import net.minidev.json.parser.ParseException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import static com.jayway.jsonpath.internal.filter.ValueNodes.*;
public abstract class ValueNode {
public static final NullNode NULL_NODE = new NullNode();
public static final BooleanNode TRUE = new BooleanNode("true");
public static final BooleanNode FALSE = new BooleanNode("false");
public static final UndefinedNode UNDEFINED = new UndefinedNode();
public abstract Class<?> type(Predicate.PredicateContext ctx);
public boolean isPatternNode() {
@ -174,7 +151,7 @@ public abstract class ValueNode {
//
//----------------------------------------------------
public static ValueNode toValueNode(Object o){
if(o == null) return ValueNode.NULL_NODE;
if(o == null) return NULL_NODE;
if(o instanceof ValueNode) return (ValueNode)o;
if(o instanceof Class) return createClassNode((Class)o);
else if(isPath(o)) return new PathNode(o.toString(), false, false);
@ -235,624 +212,5 @@ public abstract class ValueNode {
return new PathNode(path);
}
//----------------------------------------------------
//
// ValueNode Implementations
//
//----------------------------------------------------
public static class PatternNode extends ValueNode {
private final String pattern;
private final Pattern compiledPattern;
private PatternNode(CharSequence charSequence) {
String tmp = charSequence.toString();
int begin = tmp.indexOf('/');
int end = tmp.lastIndexOf('/');
int flags = tmp.endsWith("/i") ? Pattern.CASE_INSENSITIVE : 0;
this.pattern = tmp.substring(begin + 1, end);
this.compiledPattern = Pattern.compile(pattern, flags);
}
public PatternNode(Pattern pattern) {
this.pattern = pattern.pattern();
this.compiledPattern = pattern;
}
public Pattern getCompiledPattern() {
return compiledPattern;
}
@Override
public Class<?> type(Predicate.PredicateContext ctx) {
return Void.TYPE;
}
public boolean isPatternNode() {
return true;
}
public PatternNode asPatternNode() {
return this;
}
@Override
public String toString() {
String flags = "";
if((compiledPattern.flags() & Pattern.CASE_INSENSITIVE) == Pattern.CASE_INSENSITIVE){
flags = "i";
}
if(!pattern.startsWith("/")){
return "/" + pattern + "/" + flags;
} else {
return pattern;
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof PatternNode)) return false;
PatternNode that = (PatternNode) o;
return !(compiledPattern != null ? !compiledPattern.equals(that.compiledPattern) : that.compiledPattern != null);
}
}
public static class JsonNode extends ValueNode {
private final Object json;
private final boolean parsed;
private JsonNode(CharSequence charSequence) {
json = charSequence.toString();
parsed = false;
}
public JsonNode(Object parsedJson) {
json = parsedJson;
parsed = true;
}
@Override
public Class<?> type(Predicate.PredicateContext ctx) {
if(isArray(ctx)) return List.class;
else if(isMap(ctx)) return Map.class;
else if(parse(ctx) instanceof Number) return Number.class;
else if(parse(ctx) instanceof String) return String.class;
else if(parse(ctx) instanceof Boolean) return Boolean.class;
else return Void.class;
}
public boolean isJsonNode() {
return true;
}
public JsonNode asJsonNode() {
return this;
}
public ValueNode asValueListNode(Predicate.PredicateContext ctx){
if(!isArray(ctx)){
return UNDEFINED;
} else {
return new ValueListNode(Collections.unmodifiableList((List) parse(ctx)));
}
}
public Object parse(Predicate.PredicateContext ctx){
try {
return parsed ? json : new JSONParser(JSONParser.MODE_PERMISSIVE).parse(json.toString());
} catch (ParseException e) {
throw new IllegalArgumentException(e);
}
}
public boolean isParsed() {
return parsed;
}
public Object getJson() {
return json;
}
public boolean isArray(Predicate.PredicateContext ctx) {
return parse(ctx) instanceof List;
}
public boolean isMap(Predicate.PredicateContext ctx) {
return parse(ctx) instanceof Map;
}
public int length(Predicate.PredicateContext ctx) {
return isArray(ctx) ? ((List<?>) parse(ctx)).size() : -1;
}
public boolean isEmpty(Predicate.PredicateContext ctx) {
if (isArray(ctx) || isMap(ctx)) return ((Collection<?>) parse(ctx)).size() == 0;
else if((parse(ctx) instanceof String)) return ((String)parse(ctx)).length() == 0;
return true;
}
@Override
public String toString() {
return json.toString();
}
public boolean equals(JsonNode jsonNode, Predicate.PredicateContext ctx) {
if (this == jsonNode) return true;
return !(json != null ? !json.equals(jsonNode.parse(ctx)) : jsonNode.json != null);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof JsonNode)) return false;
JsonNode jsonNode = (JsonNode) o;
return !(json != null ? !json.equals(jsonNode.json) : jsonNode.json != null);
}
}
public static class StringNode extends ValueNode {
private final String string;
private boolean useSingleQuote = true;
private StringNode(CharSequence charSequence, boolean escape) {
if(charSequence.length() > 1){
char open = charSequence.charAt(0);
char close = charSequence.charAt(charSequence.length()-1);
if(open == '\'' && close == '\''){
charSequence = charSequence.subSequence(1, charSequence.length()-1);
} else if(open == '"' && close == '"'){
charSequence = charSequence.subSequence(1, charSequence.length()-1);
useSingleQuote = false;
}
}
string = escape ? Utils.unescape(charSequence.toString()) : charSequence.toString();
}
@Override
public NumberNode asNumberNode() {
BigDecimal number = null;
try {
number = new BigDecimal(string);
} catch (NumberFormatException nfe){
return NumberNode.NAN;
}
return new NumberNode(number);
}
public String getString() {
return string;
}
public int length(){
return getString().length();
}
public boolean isEmpty(){
return getString().isEmpty();
}
public boolean contains(String str) {
return getString().contains(str);
}
@Override
public Class<?> type(Predicate.PredicateContext ctx) {
return String.class;
}
public boolean isStringNode() {
return true;
}
public StringNode asStringNode() {
return this;
}
@Override
public String toString() {
String quote = useSingleQuote ? "'" : "\"";
return quote + Utils.escape(string, true) + quote;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof StringNode) && !(o instanceof NumberNode)) return false;
StringNode that = ((ValueNode) o).asStringNode();
return !(string != null ? !string.equals(that.getString()) : that.getString() != null);
}
}
public static class NumberNode extends ValueNode {
public static NumberNode NAN = new NumberNode((BigDecimal)null);
private final BigDecimal number;
private NumberNode(BigDecimal number) {
this.number = number;
}
private NumberNode(CharSequence num) {
number = new BigDecimal(num.toString());
}
@Override
public StringNode asStringNode() {
return new StringNode(number.toString(), false);
}
public BigDecimal getNumber() {
return number;
}
@Override
public Class<?> type(Predicate.PredicateContext ctx) {
return Number.class;
}
public boolean isNumberNode() {
return true;
}
public NumberNode asNumberNode() {
return this;
}
@Override
public String toString() {
return number.toString();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof NumberNode) && !(o instanceof StringNode)) return false;
NumberNode that = ((ValueNode)o).asNumberNode();
if(that == NumberNode.NAN){
return false;
} else {
return number.compareTo(that.number) == 0;
}
}
}
public static class BooleanNode extends ValueNode {
private final Boolean value;
private BooleanNode(CharSequence boolValue) {
value = Boolean.parseBoolean(boolValue.toString());
}
@Override
public Class<?> type(Predicate.PredicateContext ctx) {
return Boolean.class;
}
public boolean isBooleanNode() {
return true;
}
public BooleanNode asBooleanNode() {
return this;
}
public boolean getBoolean() {
return value;
}
@Override
public String toString() {
return value.toString();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof BooleanNode)) return false;
BooleanNode that = (BooleanNode) o;
return !(value != null ? !value.equals(that.value) : that.value != null);
}
}
public static class ClassNode extends ValueNode {
private final Class clazz;
private ClassNode(Class clazz) {
this.clazz = clazz;
}
@Override
public Class<?> type(Predicate.PredicateContext ctx) {
return Class.class;
}
public boolean isClassNode() {
return true;
}
public ClassNode asClassNode() {
return this;
}
public Class getClazz() {
return clazz;
}
@Override
public String toString() {
return clazz.getName();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ClassNode)) return false;
ClassNode that = (ClassNode) o;
return !(clazz != null ? !clazz.equals(that.clazz) : that.clazz != null);
}
}
public static class NullNode extends ValueNode {
private NullNode() {}
@Override
public Class<?> type(Predicate.PredicateContext ctx) {
return Void.class;
}
@Override
public boolean isNullNode() {
return true;
}
@Override
public NullNode asNullNode() {
return this;
}
@Override
public String toString() {
return "null";
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof NullNode)) return false;
return true;
}
}
public static class UndefinedNode extends ValueNode {
@Override
public Class<?> type(Predicate.PredicateContext ctx) {
return Void.class;
}
public UndefinedNode asUndefinedNode() {
return this;
}
public boolean isUndefinedNode() {
return true;
}
@Override
public boolean equals(Object o) {
return false;
}
}
public static class PredicateNode extends ValueNode {
private final Predicate predicate;
public PredicateNode(Predicate predicate) {
this.predicate = predicate;
}
public Predicate getPredicate() {
return predicate;
}
public PredicateNode asPredicateNode() {
return this;
}
@Override
public Class<?> type(Predicate.PredicateContext ctx) {
return Void.class;
}
public boolean isPredicateNode() {
return true;
}
@Override
public boolean equals(Object o) {
return false;
}
@Override
public String toString() {
return predicate.toString();
}
}
public static class ValueListNode extends ValueNode implements Iterable<ValueNode> {
private List<ValueNode> nodes = new ArrayList<ValueNode>();
public ValueListNode(Collection<?> values) {
for (Object value : values) {
nodes.add(toValueNode(value));
}
}
public boolean contains(ValueNode node){
return nodes.contains(node);
}
public boolean subsetof(ValueListNode right) {
for (ValueNode leftNode : nodes) {
if (!right.nodes.contains(leftNode)) {
return false;
}
}
return true;
}
public List<ValueNode> getNodes() {
return Collections.unmodifiableList(nodes);
}
@Override
public Class<?> type(Predicate.PredicateContext ctx) {
return List.class;
}
public boolean isValueListNode() {
return true;
}
public ValueListNode asValueListNode() {
return this;
}
@Override
public String toString() {
return "[" + Utils.join(",", nodes) + "]";
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ValueListNode)) return false;
ValueListNode that = (ValueListNode) o;
return !(that != null ? !nodes.equals(that.nodes) : that.nodes != null);
}
@Override
public Iterator<ValueNode> iterator() {
return nodes.iterator();
}
}
public static class PathNode extends ValueNode {
private static final Logger logger = LoggerFactory.getLogger(PathNode.class);
private final Path path;
private final boolean existsCheck;
private final boolean shouldExist;
PathNode(Path path) {
this(path, false, false);
}
PathNode(CharSequence charSequence, boolean existsCheck, boolean shouldExist) {
this(PathCompiler.compile(charSequence.toString()), existsCheck, shouldExist);
}
PathNode(Path path, boolean existsCheck, boolean shouldExist) {
this.path = path;
this.existsCheck = existsCheck;
this.shouldExist = shouldExist;
logger.trace("PathNode {} existsCheck: {}", path, existsCheck);
}
public Path getPath() {
return path;
}
public boolean isExistsCheck() {
return existsCheck;
}
public boolean shouldExists() {
return shouldExist;
}
@Override
public Class<?> type(Predicate.PredicateContext ctx) {
return Void.class;
}
public boolean isPathNode() {
return true;
}
public PathNode asPathNode() {
return this;
}
public PathNode asExistsCheck(boolean shouldExist) {
return new PathNode(path, true, shouldExist);
}
@Override
public String toString() {
return existsCheck && ! shouldExist ? Utils.concat("!" , path.toString()) : path.toString();
}
public ValueNode evaluate(Predicate.PredicateContext ctx) {
if (isExistsCheck()) {
try {
Configuration c = Configuration.builder().jsonProvider(ctx.configuration().jsonProvider()).options(Option.REQUIRE_PROPERTIES).build();
Object result = path.evaluate(ctx.item(), ctx.root(), c).getValue(false);
return result == JsonProvider.UNDEFINED ? ValueNode.FALSE : ValueNode.TRUE;
} catch (PathNotFoundException e) {
return ValueNode.FALSE;
}
} else {
try {
Object res;
if (ctx instanceof PredicateContextImpl) {
//This will use cache for document ($) queries
PredicateContextImpl ctxi = (PredicateContextImpl) ctx;
res = ctxi.evaluate(path);
} else {
Object doc = path.isRootPath() ? ctx.root() : ctx.item();
res = path.evaluate(doc, ctx.root(), ctx.configuration()).getValue();
}
res = ctx.configuration().jsonProvider().unwrap(res);
if (res instanceof Number) return ValueNode.createNumberNode(res.toString());
else if (res instanceof BigDecimal) return ValueNode.createNumberNode(res.toString());
else if (res instanceof String) return ValueNode.createStringNode(res.toString(), false);
else if (res instanceof Boolean) return ValueNode.createBooleanNode(res.toString());
else if (res == null) return ValueNode.NULL_NODE;
else if (ctx.configuration().jsonProvider().isArray(res)) return ValueNode.createJsonNode(ctx.configuration().mappingProvider().map(res, List.class, ctx.configuration()));
else if (ctx.configuration().jsonProvider().isMap(res)) return ValueNode.createJsonNode(ctx.configuration().mappingProvider().map(res, Map.class, ctx.configuration()));
else throw new JsonPathException("Could not convert " + res.toString() + " to a ValueNode");
} catch (PathNotFoundException e) {
return ValueNode.UNDEFINED;
}
}
}
}
}

662
json-path/src/main/java/com/jayway/jsonpath/internal/filter/ValueNodes.java

@ -0,0 +1,662 @@
package com.jayway.jsonpath.internal.filter;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import com.jayway.jsonpath.Configuration;
import com.jayway.jsonpath.JsonPathException;
import com.jayway.jsonpath.Option;
import com.jayway.jsonpath.PathNotFoundException;
import com.jayway.jsonpath.Predicate;
import com.jayway.jsonpath.internal.Path;
import com.jayway.jsonpath.internal.Utils;
import com.jayway.jsonpath.internal.path.PathCompiler;
import com.jayway.jsonpath.internal.path.PredicateContextImpl;
import com.jayway.jsonpath.spi.json.JsonProvider;
import net.minidev.json.parser.JSONParser;
import net.minidev.json.parser.ParseException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Moved these nodes out of the ValueNode abstract class.
* This is to avoid this possible issue:
*
* Classes that refer to their own subclasses in their static initializers or in static fields.
* Such references can cause JVM-level deadlocks in multithreaded environment, when
* one thread tries to load superclass and another thread tries to load subclass at the same time.
*/
public interface ValueNodes {
NullNode NULL_NODE = new NullNode();
BooleanNode TRUE = new BooleanNode("true");
BooleanNode FALSE = new BooleanNode("false");
UndefinedNode UNDEFINED = new UndefinedNode();
//----------------------------------------------------
//
// ValueNode Implementations
//
//----------------------------------------------------
class PatternNode extends ValueNode {
private final String pattern;
private final Pattern compiledPattern;
PatternNode(CharSequence charSequence) {
String tmp = charSequence.toString();
int begin = tmp.indexOf('/');
int end = tmp.lastIndexOf('/');
int flags = tmp.endsWith("/i") ? Pattern.CASE_INSENSITIVE : 0;
this.pattern = tmp.substring(begin + 1, end);
this.compiledPattern = Pattern.compile(pattern, flags);
}
PatternNode(Pattern pattern) {
this.pattern = pattern.pattern();
this.compiledPattern = pattern;
}
Pattern getCompiledPattern() {
return compiledPattern;
}
@Override
public Class<?> type(Predicate.PredicateContext ctx) {
return Void.TYPE;
}
public boolean isPatternNode() {
return true;
}
public PatternNode asPatternNode() {
return this;
}
@Override
public String toString() {
String flags = "";
if((compiledPattern.flags() & Pattern.CASE_INSENSITIVE) == Pattern.CASE_INSENSITIVE){
flags = "i";
}
if(!pattern.startsWith("/")){
return "/" + pattern + "/" + flags;
} else {
return pattern;
}
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof PatternNode)) return false;
PatternNode that = (PatternNode) o;
return !(compiledPattern != null ? !compiledPattern.equals(that.compiledPattern) : that.compiledPattern != null);
}
}
class JsonNode extends ValueNode {
private final Object json;
private final boolean parsed;
JsonNode(CharSequence charSequence) {
json = charSequence.toString();
parsed = false;
}
JsonNode(Object parsedJson) {
json = parsedJson;
parsed = true;
}
@Override
public Class<?> type(Predicate.PredicateContext ctx) {
if(isArray(ctx)) return List.class;
else if(isMap(ctx)) return Map.class;
else if(parse(ctx) instanceof Number) return Number.class;
else if(parse(ctx) instanceof String) return String.class;
else if(parse(ctx) instanceof Boolean) return Boolean.class;
else return Void.class;
}
public boolean isJsonNode() {
return true;
}
public JsonNode asJsonNode() {
return this;
}
public ValueNode asValueListNode(Predicate.PredicateContext ctx){
if(!isArray(ctx)){
return UNDEFINED;
} else {
return new ValueListNode(Collections.unmodifiableList((List) parse(ctx)));
}
}
public Object parse(Predicate.PredicateContext ctx){
try {
return parsed ? json : new JSONParser(JSONParser.MODE_PERMISSIVE).parse(json.toString());
} catch (ParseException e) {
throw new IllegalArgumentException(e);
}
}
public boolean isParsed() {
return parsed;
}
public Object getJson() {
return json;
}
public boolean isArray(Predicate.PredicateContext ctx) {
return parse(ctx) instanceof List;
}
public boolean isMap(Predicate.PredicateContext ctx) {
return parse(ctx) instanceof Map;
}
public int length(Predicate.PredicateContext ctx) {
return isArray(ctx) ? ((List<?>) parse(ctx)).size() : -1;
}
public boolean isEmpty(Predicate.PredicateContext ctx) {
if (isArray(ctx) || isMap(ctx)) return ((Collection<?>) parse(ctx)).size() == 0;
else if((parse(ctx) instanceof String)) return ((String)parse(ctx)).length() == 0;
return true;
}
@Override
public String toString() {
return json.toString();
}
public boolean equals(JsonNode jsonNode, Predicate.PredicateContext ctx) {
if (this == jsonNode) return true;
return !(json != null ? !json.equals(jsonNode.parse(ctx)) : jsonNode.json != null);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof JsonNode)) return false;
JsonNode jsonNode = (JsonNode) o;
return !(json != null ? !json.equals(jsonNode.json) : jsonNode.json != null);
}
}
class StringNode extends ValueNode {
private final String string;
private boolean useSingleQuote = true;
StringNode(CharSequence charSequence, boolean escape) {
if (escape && charSequence.length() > 1) {
char open = charSequence.charAt(0);
char close = charSequence.charAt(charSequence.length()-1);
if (open == '\'' && close == '\'') {
charSequence = charSequence.subSequence(1, charSequence.length()-1);
} else if (open == '"' && close == '"') {
charSequence = charSequence.subSequence(1, charSequence.length()-1);
useSingleQuote = false;
}
string = Utils.unescape(charSequence.toString());
} else {
string = charSequence.toString();
}
}
@Override
public NumberNode asNumberNode() {
BigDecimal number = null;
try {
number = new BigDecimal(string);
} catch (NumberFormatException nfe){
return NumberNode.NAN;
}
return new NumberNode(number);
}
public String getString() {
return string;
}
public int length(){
return getString().length();
}
public boolean isEmpty(){
return getString().isEmpty();
}
public boolean contains(String str) {
return getString().contains(str);
}
@Override
public Class<?> type(Predicate.PredicateContext ctx) {
return String.class;
}
public boolean isStringNode() {
return true;
}
public StringNode asStringNode() {
return this;
}
@Override
public String toString() {
String quote = useSingleQuote ? "'" : "\"";
return quote + Utils.escape(string, true) + quote;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof StringNode) && !(o instanceof NumberNode)) return false;
StringNode that = ((ValueNode) o).asStringNode();
return !(string != null ? !string.equals(that.getString()) : that.getString() != null);
}
}
class NumberNode extends ValueNode {
public static NumberNode NAN = new NumberNode((BigDecimal)null);
private final BigDecimal number;
NumberNode(BigDecimal number) {
this.number = number;
}
NumberNode(CharSequence num) {
number = new BigDecimal(num.toString());
}
@Override
public StringNode asStringNode() {
return new StringNode(number.toString(), false);
}
public BigDecimal getNumber() {
return number;
}
@Override
public Class<?> type(Predicate.PredicateContext ctx) {
return Number.class;
}
public boolean isNumberNode() {
return true;
}
public NumberNode asNumberNode() {
return this;
}
@Override
public String toString() {
return number.toString();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof NumberNode) && !(o instanceof StringNode)) return false;
NumberNode that = ((ValueNode)o).asNumberNode();
if(that == NumberNode.NAN){
return false;
} else {
return number.compareTo(that.number) == 0;
}
}
}
class BooleanNode extends ValueNode {
private final Boolean value;
private BooleanNode(CharSequence boolValue) {
value = Boolean.parseBoolean(boolValue.toString());
}
@Override
public Class<?> type(Predicate.PredicateContext ctx) {
return Boolean.class;
}
public boolean isBooleanNode() {
return true;
}
public BooleanNode asBooleanNode() {
return this;
}
public boolean getBoolean() {
return value;
}
@Override
public String toString() {
return value.toString();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof BooleanNode)) return false;
BooleanNode that = (BooleanNode) o;
return !(value != null ? !value.equals(that.value) : that.value != null);
}
}
class ClassNode extends ValueNode {
private final Class clazz;
ClassNode(Class clazz) {
this.clazz = clazz;
}
@Override
public Class<?> type(Predicate.PredicateContext ctx) {
return Class.class;
}
public boolean isClassNode() {
return true;
}
public ClassNode asClassNode() {
return this;
}
public Class getClazz() {
return clazz;
}
@Override
public String toString() {
return clazz.getName();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ClassNode)) return false;
ClassNode that = (ClassNode) o;
return !(clazz != null ? !clazz.equals(that.clazz) : that.clazz != null);
}
}
class NullNode extends ValueNode {
private NullNode() {}
@Override
public Class<?> type(Predicate.PredicateContext ctx) {
return Void.class;
}
@Override
public boolean isNullNode() {
return true;
}
@Override
public NullNode asNullNode() {
return this;
}
@Override
public String toString() {
return "null";
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof NullNode)) return false;
return true;
}
}
class UndefinedNode extends ValueNode {
@Override
public Class<?> type(Predicate.PredicateContext ctx) {
return Void.class;
}
public UndefinedNode asUndefinedNode() {
return this;
}
public boolean isUndefinedNode() {
return true;
}
@Override
public boolean equals(Object o) {
return false;
}
}
class PredicateNode extends ValueNode {
private final Predicate predicate;
public PredicateNode(Predicate predicate) {
this.predicate = predicate;
}
public Predicate getPredicate() {
return predicate;
}
public PredicateNode asPredicateNode() {
return this;
}
@Override
public Class<?> type(Predicate.PredicateContext ctx) {
return Void.class;
}
public boolean isPredicateNode() {
return true;
}
@Override
public boolean equals(Object o) {
return false;
}
@Override
public String toString() {
return predicate.toString();
}
}
class ValueListNode extends ValueNode implements Iterable<ValueNode> {
private List<ValueNode> nodes = new ArrayList<ValueNode>();
public ValueListNode(Collection<?> values) {
for (Object value : values) {
nodes.add(toValueNode(value));
}
}
public boolean contains(ValueNode node){
return nodes.contains(node);
}
public boolean subsetof(ValueListNode right) {
for (ValueNode leftNode : nodes) {
if (!right.nodes.contains(leftNode)) {
return false;
}
}
return true;
}
public List<ValueNode> getNodes() {
return Collections.unmodifiableList(nodes);
}
@Override
public Class<?> type(Predicate.PredicateContext ctx) {
return List.class;
}
public boolean isValueListNode() {
return true;
}
public ValueListNode asValueListNode() {
return this;
}
@Override
public String toString() {
return "[" + Utils.join(",", nodes) + "]";
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ValueListNode)) return false;
ValueListNode that = (ValueListNode) o;
return nodes.equals(that.nodes);
}
@Override
public Iterator<ValueNode> iterator() {
return nodes.iterator();
}
}
class PathNode extends ValueNode {
private static final Logger logger = LoggerFactory.getLogger(PathNode.class);
private final Path path;
private final boolean existsCheck;
private final boolean shouldExist;
PathNode(Path path) {
this(path, false, false);
}
PathNode(CharSequence charSequence, boolean existsCheck, boolean shouldExist) {
this(PathCompiler.compile(charSequence.toString()), existsCheck, shouldExist);
}
PathNode(Path path, boolean existsCheck, boolean shouldExist) {
this.path = path;
this.existsCheck = existsCheck;
this.shouldExist = shouldExist;
logger.trace("PathNode {} existsCheck: {}", path, existsCheck);
}
public Path getPath() {
return path;
}
public boolean isExistsCheck() {
return existsCheck;
}
public boolean shouldExists() {
return shouldExist;
}
@Override
public Class<?> type(Predicate.PredicateContext ctx) {
return Void.class;
}
public boolean isPathNode() {
return true;
}
public PathNode asPathNode() {
return this;
}
public PathNode asExistsCheck(boolean shouldExist) {
return new PathNode(path, true, shouldExist);
}
@Override
public String toString() {
return existsCheck && ! shouldExist ? Utils.concat("!" , path.toString()) : path.toString();
}
public ValueNode evaluate(Predicate.PredicateContext ctx) {
if (isExistsCheck()) {
try {
Configuration c = Configuration.builder().jsonProvider(ctx.configuration().jsonProvider()).options(Option.REQUIRE_PROPERTIES).build();
Object result = path.evaluate(ctx.item(), ctx.root(), c).getValue(false);
return result == JsonProvider.UNDEFINED ? FALSE : TRUE;
} catch (PathNotFoundException e) {
return FALSE;
}
} else {
try {
Object res;
if (ctx instanceof PredicateContextImpl) {
//This will use cache for document ($) queries
PredicateContextImpl ctxi = (PredicateContextImpl) ctx;
res = ctxi.evaluate(path);
} else {
Object doc = path.isRootPath() ? ctx.root() : ctx.item();
res = path.evaluate(doc, ctx.root(), ctx.configuration()).getValue();
}
res = ctx.configuration().jsonProvider().unwrap(res);
if (res instanceof Number) return ValueNode.createNumberNode(res.toString());
else if (res instanceof String) return ValueNode.createStringNode(res.toString(), false);
else if (res instanceof Boolean) return ValueNode.createBooleanNode(res.toString());
else if (res == null) return NULL_NODE;
else if (ctx.configuration().jsonProvider().isArray(res)) return ValueNode.createJsonNode(ctx.configuration().mappingProvider().map(res, List.class, ctx.configuration()));
else if (ctx.configuration().jsonProvider().isMap(res)) return ValueNode.createJsonNode(ctx.configuration().mappingProvider().map(res, Map.class, ctx.configuration()));
else throw new JsonPathException("Could not convert " + res.toString() + " to a ValueNode");
} catch (PathNotFoundException e) {
return UNDEFINED;
}
}
}
}
}

2
json-path/src/main/java/com/jayway/jsonpath/internal/function/text/Concatenate.java

@ -15,7 +15,7 @@ import java.util.List;
public class Concatenate implements PathFunction {
@Override
public Object invoke(String currentPath, PathRef parent, Object model, EvaluationContext ctx, List<Parameter> parameters) {
StringBuffer result = new StringBuffer();
StringBuilder result = new StringBuilder();
if(ctx.configuration().jsonProvider().isArray(model)){
Iterable<?> objects = ctx.configuration().jsonProvider().toIterable(model);
for (Object obj : objects) {

52
json-path/src/main/java/com/jayway/jsonpath/internal/path/ArrayIndexToken.java

@ -0,0 +1,52 @@
/*
* Copyright 2011 the original author or authors.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jayway.jsonpath.internal.path;
import com.jayway.jsonpath.internal.PathRef;
import static java.lang.String.format;
public class ArrayIndexToken extends ArrayPathToken {
private final ArrayIndexOperation arrayIndexOperation;
ArrayIndexToken(final ArrayIndexOperation arrayIndexOperation) {
this.arrayIndexOperation = arrayIndexOperation;
}
@Override
public void evaluate(String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx) {
if (!checkArrayModel(currentPath, model, ctx))
return;
if (arrayIndexOperation.isSingleIndexOperation()) {
handleArrayIndex(arrayIndexOperation.indexes().get(0), currentPath, model, ctx);
} else {
for (Integer index : arrayIndexOperation.indexes()) {
handleArrayIndex(index, currentPath, model, ctx);
}
}
}
@Override
public String getPathFragment() {
return arrayIndexOperation.toString();
}
@Override
public boolean isTokenDefinite() {
return arrayIndexOperation.isSingleIndexOperation();
}
}

138
json-path/src/main/java/com/jayway/jsonpath/internal/path/ArrayPathToken.java

@ -22,143 +22,7 @@ import org.slf4j.LoggerFactory;
import static java.lang.String.format;
/**
*
*/
public class ArrayPathToken extends PathToken {
private static final Logger logger = LoggerFactory.getLogger(ArrayPathToken.class);
private final ArraySliceOperation arraySliceOperation;
private final ArrayIndexOperation arrayIndexOperation;
ArrayPathToken(final ArraySliceOperation arraySliceOperation) {
this.arraySliceOperation = arraySliceOperation;
this.arrayIndexOperation = null;
}
ArrayPathToken(final ArrayIndexOperation arrayIndexOperation) {
this.arrayIndexOperation = arrayIndexOperation;
this.arraySliceOperation = null;
}
@Override
public void evaluate(String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx) {
if (! checkArrayModel(currentPath, model, ctx))
return;
if(arraySliceOperation != null){
evaluateSliceOperation(currentPath, parent, model, ctx);
} else {
evaluateIndexOperation(currentPath, parent, model, ctx);
}
}
public void evaluateIndexOperation(String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx) {
if (! checkArrayModel(currentPath, model, ctx))
return;
if(arrayIndexOperation.isSingleIndexOperation()){
handleArrayIndex(arrayIndexOperation.indexes().get(0), currentPath, model, ctx);
} else {
for (Integer index : arrayIndexOperation.indexes()) {
handleArrayIndex(index, currentPath, model, ctx);
}
}
}
public void evaluateSliceOperation(String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx) {
if (! checkArrayModel(currentPath, model, ctx))
return;
switch (arraySliceOperation.operation()) {
case SLICE_FROM:
sliceFrom(arraySliceOperation, currentPath, parent, model, ctx);
break;
case SLICE_BETWEEN:
sliceBetween(arraySliceOperation, currentPath, parent, model, ctx);
break;
case SLICE_TO:
sliceTo(arraySliceOperation, currentPath, parent, model, ctx);
break;
}
}
public void sliceFrom(ArraySliceOperation operation, String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx) {
int length = ctx.jsonProvider().length(model);
int from = operation.from();
if (from < 0) {
//calculate slice start from array length
from = length + from;
}
from = Math.max(0, from);
logger.debug("Slice from index on array with length: {}. From index: {} to: {}. Input: {}", length, from, length - 1, toString());
if (length == 0 || from >= length) {
return;
}
for (int i = from; i < length; i++) {
handleArrayIndex(i, currentPath, model, ctx);
}
}
public void sliceBetween(ArraySliceOperation operation, String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx) {
int length = ctx.jsonProvider().length(model);
int from = operation.from();
int to = operation.to();
to = Math.min(length, to);
if (from >= to || length == 0) {
return;
}
logger.debug("Slice between indexes on array with length: {}. From index: {} to: {}. Input: {}", length, from, to, toString());
for (int i = from; i < to; i++) {
handleArrayIndex(i, currentPath, model, ctx);
}
}
public void sliceTo(ArraySliceOperation operation, String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx) {
int length = ctx.jsonProvider().length(model);
if (length == 0) {
return;
}
int to = operation.to();
if (to < 0) {
//calculate slice end from array length
to = length + to;
}
to = Math.min(length, to);
logger.debug("Slice to index on array with length: {}. From index: 0 to: {}. Input: {}", length, to, toString());
for (int i = 0; i < to; i++) {
handleArrayIndex(i, currentPath, model, ctx);
}
}
@Override
public String getPathFragment() {
if(arrayIndexOperation != null){
return arrayIndexOperation.toString();
} else {
return arraySliceOperation.toString();
}
}
@Override
public boolean isTokenDefinite() {
if(arrayIndexOperation != null){
return arrayIndexOperation.isSingleIndexOperation();
} else {
return false;
}
}
public abstract class ArrayPathToken extends PathToken {
/**
* Check if model is non-null and array.

18
json-path/src/main/java/com/jayway/jsonpath/internal/path/ArraySliceOperation.java

@ -58,19 +58,19 @@ public class ArraySliceOperation {
Integer tempFrom = tryRead(tokens, 0);
Integer tempTo = tryRead(tokens, 1);
Operation tempOperpation;
if(tempFrom != null && tempTo == null){
tempOperpation = Operation.SLICE_FROM;
} else if(tempFrom != null && tempTo != null){
tempOperpation = Operation.SLICE_BETWEEN;
} else if(tempFrom == null && tempTo != null){
tempOperpation = Operation.SLICE_TO;
Operation tempOperation;
if (tempFrom != null && tempTo == null) {
tempOperation = Operation.SLICE_FROM;
} else if (tempFrom != null) {
tempOperation = Operation.SLICE_BETWEEN;
} else if (tempTo != null) {
tempOperation = Operation.SLICE_TO;
} else {
throw new InvalidPathException("Failed to parse SliceOperation: " + operation);
}
return new ArraySliceOperation(tempFrom, tempTo, tempOperpation);
return new ArraySliceOperation(tempFrom, tempTo, tempOperation);
}
private static Integer tryRead(String[] tokens, int idx){

114
json-path/src/main/java/com/jayway/jsonpath/internal/path/ArraySliceToken.java

@ -0,0 +1,114 @@
/*
* Copyright 2011 the original author or authors.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.jayway.jsonpath.internal.path;
import com.jayway.jsonpath.internal.PathRef;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ArraySliceToken extends ArrayPathToken {
private static final Logger logger = LoggerFactory.getLogger(ArraySliceToken.class);
private final ArraySliceOperation operation;
ArraySliceToken(final ArraySliceOperation operation) {
this.operation = operation;
}
@Override
public void evaluate(String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx) {
if (!checkArrayModel(currentPath, model, ctx))
return;
switch (operation.operation()) {
case SLICE_FROM:
sliceFrom(currentPath, parent, model, ctx);
break;
case SLICE_BETWEEN:
sliceBetween(currentPath, parent, model, ctx);
break;
case SLICE_TO:
sliceTo(currentPath, parent, model, ctx);
break;
}
}
private void sliceFrom(String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx) {
int length = ctx.jsonProvider().length(model);
int from = operation.from();
if (from < 0) {
//calculate slice start from array length
from = length + from;
}
from = Math.max(0, from);
logger.debug("Slice from index on array with length: {}. From index: {} to: {}. Input: {}", length, from, length - 1, toString());
if (length == 0 || from >= length) {
return;
}
for (int i = from; i < length; i++) {
handleArrayIndex(i, currentPath, model, ctx);
}
}
private void sliceBetween(String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx) {
int length = ctx.jsonProvider().length(model);
int from = operation.from();
int to = operation.to();
to = Math.min(length, to);
if (from >= to || length == 0) {
return;
}
logger.debug("Slice between indexes on array with length: {}. From index: {} to: {}. Input: {}", length, from, to, toString());
for (int i = from; i < to; i++) {
handleArrayIndex(i, currentPath, model, ctx);
}
}
private void sliceTo(String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx) {
int length = ctx.jsonProvider().length(model);
if (length == 0) {
return;
}
int to = operation.to();
if (to < 0) {
//calculate slice end from array length
to = length + to;
}
to = Math.min(length, to);
logger.debug("Slice to index on array with length: {}. From index: 0 to: {}. Input: {}", length, to, toString());
for (int i = 0; i < to; i++) {
handleArrayIndex(i, currentPath, model, ctx);
}
}
@Override
public String getPathFragment() {
return operation.toString();
}
@Override
public boolean isTokenDefinite() {
return false;
}
}

2
json-path/src/main/java/com/jayway/jsonpath/internal/path/CompiledPath.java

@ -97,7 +97,7 @@ public class CompiledPath implements Path {
try {
PathRef op = ctx.forUpdate() ? PathRef.createRoot(rootDocument) : PathRef.NO_OP;
root.evaluate("", op, document, ctx);
} catch (EvaluationAbortException abort){};
} catch (EvaluationAbortException abort) {}
return ctx;
}

4
json-path/src/main/java/com/jayway/jsonpath/internal/path/PathCompiler.java

@ -275,7 +275,7 @@ public class PathCompiler {
Boolean endOfStream = false;
char priorChar = 0;
List<Parameter> parameters = new ArrayList<Parameter>();
StringBuffer parameter = new StringBuffer();
StringBuilder parameter = new StringBuilder();
while (path.inBounds() && !endOfStream) {
char c = path.currentChar();
path.incrementPosition(1);
@ -580,7 +580,7 @@ public class PathCompiler {
}
break;
} else if (c == potentialStringDelimiter) {
if (inProperty && !inEscape) {
if (inProperty) {
char nextSignificantChar = path.nextSignificantChar(readPosition);
if (nextSignificantChar != CLOSE_SQUARE_BRACKET && nextSignificantChar != COMMA) {
fail("Property must be separated by comma or Property must be terminated close square bracket at index "+readPosition);

4
json-path/src/main/java/com/jayway/jsonpath/internal/path/PathTokenFactory.java

@ -23,11 +23,11 @@ public class PathTokenFactory {
}
public static PathToken createSliceArrayPathToken(final ArraySliceOperation arraySliceOperation) {
return new ArrayPathToken(arraySliceOperation);
return new ArraySliceToken(arraySliceOperation);
}
public static PathToken createIndexArrayPathToken(final ArrayIndexOperation arrayIndexOperation) {
return new ArrayPathToken(arrayIndexOperation);
return new ArrayIndexToken(arrayIndexOperation);
}
public static PathToken createWildCardPathToken() {

3
json-path/src/main/java/com/jayway/jsonpath/internal/path/PredicatePathToken.java

@ -20,6 +20,7 @@ import com.jayway.jsonpath.Predicate;
import com.jayway.jsonpath.internal.PathRef;
import java.util.Collection;
import java.util.Collections;
import static java.lang.String.format;
import static java.util.Arrays.asList;
@ -33,7 +34,7 @@ public class PredicatePathToken extends PathToken {
private final Collection<Predicate> predicates;
PredicatePathToken(Predicate filter) {
this.predicates = asList(filter);
this.predicates = Collections.singletonList(filter);
}
PredicatePathToken(Collection<Predicate> predicates) {

2
json-path/src/main/java/com/jayway/jsonpath/internal/path/RootPathToken.java

@ -27,7 +27,7 @@ public class RootPathToken extends PathToken {
RootPathToken(char rootToken) {
this.rootToken = Character.toString(rootToken);;
this.rootToken = Character.toString(rootToken);
this.tail = this;
this.tokenCount = 1;
}

4
json-path/src/main/java/com/jayway/jsonpath/internal/path/WildcardPathToken.java

@ -14,6 +14,8 @@
*/
package com.jayway.jsonpath.internal.path;
import java.util.Collections;
import com.jayway.jsonpath.Option;
import com.jayway.jsonpath.PathNotFoundException;
import com.jayway.jsonpath.internal.PathRef;
@ -32,7 +34,7 @@ public class WildcardPathToken extends PathToken {
public void evaluate(String currentPath, PathRef parent, Object model, EvaluationContextImpl ctx) {
if (ctx.jsonProvider().isMap(model)) {
for (String property : ctx.jsonProvider().getPropertyKeys(model)) {
handleObjectProperty(currentPath, model, ctx, asList(property));
handleObjectProperty(currentPath, model, ctx, Collections.singletonList(property));
}
} else if (ctx.jsonProvider().isArray(model)) {
for (int idx = 0; idx < ctx.jsonProvider().length(model); idx++) {

4
json-path/src/main/java/com/jayway/jsonpath/spi/cache/CacheProvider.java vendored

@ -6,7 +6,6 @@ import static com.jayway.jsonpath.internal.Utils.notNull;
public class CacheProvider {
private static Cache cache;
private static boolean cachingEnabled;
public static void setCache(Cache cache){
notNull(cache, "Cache may not be null");
@ -16,7 +15,6 @@ public class CacheProvider {
} else {
CacheProvider.cache = cache;
}
cachingEnabled = !(CacheProvider.cache instanceof NOOPCache);
}
}
@ -36,4 +34,4 @@ public class CacheProvider {
return new LRUCache(400);
//return new NOOPCache();
}
}
}

2
json-path/src/main/java/com/jayway/jsonpath/spi/json/AbstractJsonProvider.java

@ -162,7 +162,7 @@ public abstract class AbstractJsonProvider implements JsonProvider {
* @return an Iterable that iterates over the entries of an array
*/
@SuppressWarnings("unchecked")
public Iterable<? extends Object> toIterable(Object obj) {
public Iterable<?> toIterable(Object obj) {
if (isArray(obj))
return ((Iterable) obj);
else

3
json-path/src/test/java/com/jayway/jsonpath/FilterTest.java

@ -279,7 +279,8 @@ public class FilterTest extends BaseTest {
Filter farr = parse("[?(@.foo == " + arr + ")]");
//Filter fobjF = parse("[?(@.foo == " + nest + ")]");
//Filter fobjT = parse("[?(@.bar == " + nest + ")]");
assertThat(farr.apply(context)).isEqualTo(true);
boolean apply = farr.apply(context);
assertThat(apply).isEqualTo(true);
//assertThat(fobjF.apply(context)).isEqualTo(false);
//assertThat(fobjT.apply(context)).isEqualTo(true);
}

3
json-path/src/test/java/com/jayway/jsonpath/MultiPropTest.java

@ -3,6 +3,7 @@ package com.jayway.jsonpath;
import org.junit.Test;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static com.jayway.jsonpath.JsonPath.using;
@ -114,7 +115,7 @@ public class MultiPropTest {
final Configuration conf = Configuration.defaultConfiguration().addOptions(Option.REQUIRE_PROPERTIES);
final String json = "{\"a\": {\"v\": 5}, \"b\": {\"v\": 4}, \"c\": {\"v\": 1}}";
assertThat(using(conf).parse(json).read("$['a', 'c'].v")).asList().containsOnly(5, 1);
assertThat((List)using(conf).parse(json).read("$['a', 'c'].v")).asList().containsOnly(5, 1);
assertEvaluationThrows(json, "$['d', 'a', 'c', 'm'].v", PathNotFoundException.class, conf);
}
}

24
json-path/src/test/java/com/jayway/jsonpath/OptionsTest.java

@ -21,7 +21,7 @@ public class OptionsTest extends BaseTest {
Configuration conf = Configuration.defaultConfiguration();
assertThat(using(conf).parse("{\"foo\" : \"bar\"}").read("$.baz")).isNull();
assertThat((String)using(conf).parse("{\"foo\" : \"bar\"}").read("$.baz")).isNull();
}
@Test
@ -37,7 +37,7 @@ public class OptionsTest extends BaseTest {
Configuration conf = Configuration.defaultConfiguration();
assertThat(using(conf).parse("{\"foo\" : \"bar\"}").read("$.foo")).isInstanceOf(String.class);
assertThat((String)using(conf).parse("{\"foo\" : \"bar\"}").read("$.foo")).isInstanceOf(String.class);
}
@Test
@ -45,11 +45,11 @@ public class OptionsTest extends BaseTest {
Configuration conf = Configuration.builder().options(ALWAYS_RETURN_LIST).build();
assertThat(using(conf).parse("{\"foo\" : \"bar\"}").read("$.foo")).isInstanceOf(List.class);
assertThat((List)using(conf).parse("{\"foo\" : \"bar\"}").read("$.foo")).isInstanceOf(List.class);
assertThat(using(conf).parse("{\"foo\": null}").read("$.foo")).isInstanceOf(List.class);
assertThat((List)using(conf).parse("{\"foo\": null}").read("$.foo")).isInstanceOf(List.class);
assertThat(using(conf).parse("{\"foo\": [1, 4, 8]}").read("$.foo")).asList()
assertThat((List)using(conf).parse("{\"foo\": [1, 4, 8]}").read("$.foo")).asList()
.containsExactly(Arrays.asList(1, 4, 8));
}
@ -61,7 +61,7 @@ public class OptionsTest extends BaseTest {
assertThat(result).hasSize(1);
assertThat(result.get(0)).isNull();
assertThat(using(conf).parse("{\"bar\": {\"foo\": [1, 4, 8]}}").read("$..foo")).asList()
assertThat((List)using(conf).parse("{\"bar\": {\"foo\": [1, 4, 8]}}").read("$..foo")).asList()
.containsExactly(Arrays.asList(1, 4, 8));
}
@ -69,7 +69,7 @@ public class OptionsTest extends BaseTest {
public void a_path_evaluation_is_returned_as_VALUE_by_default() {
Configuration conf = Configuration.defaultConfiguration();
assertThat(using(conf).parse("{\"foo\" : \"bar\"}").read("$.foo")).isEqualTo("bar");
assertThat((String)using(conf).parse("{\"foo\" : \"bar\"}").read("$.foo")).isEqualTo("bar");
}
@Test
@ -142,13 +142,13 @@ public class OptionsTest extends BaseTest {
public void issue_suppress_exceptions_does_not_break_indefinite_evaluation() {
Configuration conf = Configuration.builder().options(SUPPRESS_EXCEPTIONS).build();
assertThat(using(conf).parse("{\"foo2\": [5]}").read("$..foo2[0]")).asList().containsOnly(5);
assertThat(using(conf).parse("{\"foo\" : {\"foo2\": [5]}}").read("$..foo2[0]")).asList().containsOnly(5);
assertThat(using(conf).parse("[null, [{\"foo\" : {\"foo2\": [5]}}]]").read("$..foo2[0]")).asList().containsOnly(5);
assertThat((List)using(conf).parse("{\"foo2\": [5]}").read("$..foo2[0]")).asList().containsOnly(5);
assertThat((List)using(conf).parse("{\"foo\" : {\"foo2\": [5]}}").read("$..foo2[0]")).asList().containsOnly(5);
assertThat((List)using(conf).parse("[null, [{\"foo\" : {\"foo2\": [5]}}]]").read("$..foo2[0]")).asList().containsOnly(5);
assertThat(using(conf).parse("[null, [{\"foo\" : {\"foo2\": [5]}}]]").read("$..foo.foo2[0]")).asList().containsOnly(5);
assertThat((List)using(conf).parse("[null, [{\"foo\" : {\"foo2\": [5]}}]]").read("$..foo.foo2[0]")).asList().containsOnly(5);
assertThat(using(conf).parse("{\"aoo\" : {}, \"foo\" : {\"foo2\": [5]}, \"zoo\" : {}}").read("$[*].foo2[0]")).asList().containsOnly(5);
assertThat((List)using(conf).parse("{\"aoo\" : {}, \"foo\" : {\"foo2\": [5]}, \"zoo\" : {}}").read("$[*].foo2[0]")).asList().containsOnly(5);
}
@Test

44
json-path/src/test/java/com/jayway/jsonpath/PathCompilerTest.java

@ -1,5 +1,6 @@
package com.jayway.jsonpath;
import com.jayway.jsonpath.internal.ParseContextImpl;
import org.junit.Ignore;
import org.junit.Test;
@ -236,6 +237,49 @@ public class PathCompilerTest {
assertThat(result).hasSize(1);
}
@Test
public void issue_predicate_can_have_double_quotes() {
String json = "{\n"
+ " \"logs\": [\n"
+ " {\n"
+ " \"message\": \"\\\"it\\\"\",\n"
+ " }\n"
+ " ]\n"
+ "}";
List<String> result = JsonPath.read(json, "$.logs[?(@.message == '\"it\"')].message");
assertThat(result).containsExactly("\"it\"");
}
@Test
public void issue_predicate_can_have_single_quotes() {
String json = "{\n"
+ " \"logs\": [\n"
+ " {\n"
+ " \"message\": \"'it'\",\n"
+ " }\n"
+ " ]\n"
+ "}";
DocumentContext parse = JsonPath.parse(json);
JsonPath compile = JsonPath.compile("$.logs[?(@.message == \"'it'\")].message");
List<String> result = parse.read(compile);
assertThat(result).containsExactly("'it'");
}
@Test
public void issue_predicate_can_have_single_quotes_escaped() {
String json = "{\n"
+ " \"logs\": [\n"
+ " {\n"
+ " \"message\": \"'it'\",\n"
+ " }\n"
+ " ]\n"
+ "}";
DocumentContext parse = JsonPath.parse(json);
JsonPath compile = JsonPath.compile("$.logs[?(@.message == '\\'it\\'')].message");
List<String> result = parse.read(compile);
assertThat(result).containsExactly("'it'");
}
@Test
public void issue_predicate_can_have_square_bracket_in_prop() {
String json = "{\n"

8
json-path/src/test/java/com/jayway/jsonpath/ReturnTypeTest.java

@ -18,7 +18,7 @@ public class ReturnTypeTest extends BaseTest {
@Test
public void assert_strings_can_be_read() {
assertThat(reader.read("$.string-property")).isEqualTo("string-value");
assertThat((String)reader.read("$.string-property")).isEqualTo("string-value");
}
@Test
@ -28,17 +28,17 @@ public class ReturnTypeTest extends BaseTest {
@Test
public void assert_longs_can_be_read() {
assertThat(reader.read("$.long-max-property")).isEqualTo(Long.MAX_VALUE);
assertThat((Long)reader.read("$.long-max-property")).isEqualTo(Long.MAX_VALUE);
}
@Test
public void assert_boolean_values_can_be_read() {
assertThat(reader.read("$.boolean-property")).isEqualTo(true);
assertThat((Boolean)reader.read("$.boolean-property")).isEqualTo(true);
}
@Test
public void assert_null_values_can_be_read() {
assertThat(reader.read("$.null-property")).isNull();
assertThat((String)reader.read("$.null-property")).isNull();
}
@Test

14
json-path/src/test/java/com/jayway/jsonpath/old/IssuesTest.java

@ -431,7 +431,7 @@ public class IssuesTest extends BaseTest {
"]";
assertEquals(1, read(json, "$[0].a"));
assertEquals(Integer.valueOf(1), read(json, "$[0].a"));
}
@Test(expected = PathNotFoundException.class)
@ -471,9 +471,9 @@ public class IssuesTest extends BaseTest {
String json = "{\"test\":null}";
assertThat(read(json, "test")).isNull();
assertThat((String)read(json, "test")).isNull();
assertThat(JsonPath.using(Configuration.defaultConfiguration().setOptions(Option.SUPPRESS_EXCEPTIONS)).parse(json).read("nonExistingProperty")).isNull();
assertThat((String)JsonPath.using(Configuration.defaultConfiguration().setOptions(Option.SUPPRESS_EXCEPTIONS)).parse(json).read("nonExistingProperty")).isNull();
try {
read(json, "nonExistingProperty");
@ -498,7 +498,7 @@ public class IssuesTest extends BaseTest {
public void issue_45() {
String json = "{\"rootkey\":{\"sub.key\":\"value\"}}";
assertThat(read(json, "rootkey['sub.key']")).isEqualTo("value");
assertThat((String)read(json, "rootkey['sub.key']")).isEqualTo("value");
}
@Test
@ -508,7 +508,7 @@ public class IssuesTest extends BaseTest {
String json = "{\"a\": {}}";
Configuration configuration = Configuration.defaultConfiguration().setOptions(Option.SUPPRESS_EXCEPTIONS);
assertThat(JsonPath.using(configuration).parse(json).read("a.x")).isNull();
assertThat((String)JsonPath.using(configuration).parse(json).read("a.x")).isNull();
try {
read(json, "a.x");
@ -1018,8 +1018,8 @@ public class IssuesTest extends BaseTest {
DocumentContext doc = JsonPath.parse(json).set("$.jsonArr[1].name", "Jayway");
assertThat(doc.read("$.jsonArr[0].name")).isEqualTo("nOne");
assertThat(doc.read("$.jsonArr[1].name")).isEqualTo("Jayway");
assertThat((String)doc.read("$.jsonArr[0].name")).isEqualTo("nOne");
assertThat((String)doc.read("$.jsonArr[1].name")).isEqualTo("Jayway");
}
@Test

2
json-path/src/test/java/com/jayway/jsonpath/old/JsonPathTest.java

@ -133,7 +133,7 @@ public class JsonPathTest extends BaseTest {
Assertions.fail("Expected PathNotFoundException");
} catch (PathNotFoundException e) {
}
Assertions.assertThat(JsonPath.read(json, "$.data2.passes[0].id")).isEqualTo("1");
Assertions.assertThat((String)JsonPath.read(json, "$.data2.passes[0].id")).isEqualTo("1");
}
@Test

Loading…
Cancel
Save