|
|
@ -17,6 +17,7 @@ package com.jayway.jsonpath; |
|
|
|
import com.jayway.jsonpath.internal.Path; |
|
|
|
import com.jayway.jsonpath.internal.Path; |
|
|
|
import com.jayway.jsonpath.internal.PathCompiler; |
|
|
|
import com.jayway.jsonpath.internal.PathCompiler; |
|
|
|
import com.jayway.jsonpath.internal.token.PredicateContextImpl; |
|
|
|
import com.jayway.jsonpath.internal.token.PredicateContextImpl; |
|
|
|
|
|
|
|
import com.jayway.jsonpath.spi.json.JsonProvider; |
|
|
|
import org.slf4j.Logger; |
|
|
|
import org.slf4j.Logger; |
|
|
|
import org.slf4j.LoggerFactory; |
|
|
|
import org.slf4j.LoggerFactory; |
|
|
|
|
|
|
|
|
|
|
@ -48,6 +49,7 @@ public class Criteria implements Predicate { |
|
|
|
CriteriaType.GT.toString(), |
|
|
|
CriteriaType.GT.toString(), |
|
|
|
CriteriaType.REGEX.toString() |
|
|
|
CriteriaType.REGEX.toString() |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
private static final char BS = '\\'; |
|
|
|
|
|
|
|
|
|
|
|
private Object left; |
|
|
|
private Object left; |
|
|
|
private CriteriaType criteriaType; |
|
|
|
private CriteriaType criteriaType; |
|
|
@ -59,7 +61,7 @@ public class Criteria implements Predicate { |
|
|
|
EQ { |
|
|
|
EQ { |
|
|
|
@Override |
|
|
|
@Override |
|
|
|
boolean eval(Object expected, Object model, PredicateContext ctx) { |
|
|
|
boolean eval(Object expected, Object model, PredicateContext ctx) { |
|
|
|
boolean res = (0 == safeCompare(expected, model)); |
|
|
|
boolean res = (0 == safeCompare(expected, model, ctx)); |
|
|
|
if (logger.isDebugEnabled()) logger.debug("[{}] {} [{}] => {}", model, name(), expected, res); |
|
|
|
if (logger.isDebugEnabled()) logger.debug("[{}] {} [{}] => {}", model, name(), expected, res); |
|
|
|
return res; |
|
|
|
return res; |
|
|
|
} |
|
|
|
} |
|
|
@ -72,7 +74,7 @@ public class Criteria implements Predicate { |
|
|
|
NE { |
|
|
|
NE { |
|
|
|
@Override |
|
|
|
@Override |
|
|
|
boolean eval(Object expected, Object model, PredicateContext ctx) { |
|
|
|
boolean eval(Object expected, Object model, PredicateContext ctx) { |
|
|
|
boolean res = (0 != safeCompare(expected, model)); |
|
|
|
boolean res = (0 != safeCompare(expected, model, ctx)); |
|
|
|
if (logger.isDebugEnabled()) logger.debug("[{}] {} [{}] => {}", model, name(), expected, res); |
|
|
|
if (logger.isDebugEnabled()) logger.debug("[{}] {} [{}] => {}", model, name(), expected, res); |
|
|
|
return res; |
|
|
|
return res; |
|
|
|
} |
|
|
|
} |
|
|
@ -710,6 +712,14 @@ public class Criteria implements Predicate { |
|
|
|
return (string != null && !string.isEmpty() && string.charAt(0) == '\'' && string.charAt(string.length() - 1) == '\''); |
|
|
|
return (string != null && !string.isEmpty() && string.charAt(0) == '\'' && string.charAt(string.length() - 1) == '\''); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static boolean isJson(String string) { |
|
|
|
|
|
|
|
if (string == null || string.length() <= 1) |
|
|
|
|
|
|
|
return false; |
|
|
|
|
|
|
|
char c0 = string.charAt(0); |
|
|
|
|
|
|
|
char c1 = string.charAt(string.length() - 1); |
|
|
|
|
|
|
|
return (c0 == '[' && c1 == ']') || (c0 == '{' && c1 == '}'); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static boolean isPattern(String string) { |
|
|
|
private static boolean isPattern(String string) { |
|
|
|
return (string != null |
|
|
|
return (string != null |
|
|
|
&& !string.isEmpty() |
|
|
|
&& !string.isEmpty() |
|
|
@ -727,7 +737,6 @@ public class Criteria implements Predicate { |
|
|
|
return Pattern.compile(regex, flags); |
|
|
|
return Pattern.compile(regex, flags); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Parse the provided criteria |
|
|
|
* Parse the provided criteria |
|
|
|
* |
|
|
|
* |
|
|
@ -755,6 +764,28 @@ public class Criteria implements Predicate { |
|
|
|
return Criteria.create(left, operator, right); |
|
|
|
return Criteria.create(left, operator, right); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Wrapper for JSON to be parsed as a String. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
private static class JsonValue { |
|
|
|
|
|
|
|
final String value; |
|
|
|
|
|
|
|
volatile Object jsonValue; |
|
|
|
|
|
|
|
JsonValue(String value) { this.value = value; } |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Object parsed(PredicateContext ctx) { |
|
|
|
|
|
|
|
if (jsonValue == null) { |
|
|
|
|
|
|
|
JsonProvider provider = ctx.configuration().jsonProvider(); |
|
|
|
|
|
|
|
jsonValue = provider.parse(value); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return jsonValue; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
public String toString() { |
|
|
|
|
|
|
|
return getClass().getSimpleName() + " " + value; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Creates a new criteria |
|
|
|
* Creates a new criteria |
|
|
|
* |
|
|
|
* |
|
|
@ -797,6 +828,8 @@ public class Criteria implements Predicate { |
|
|
|
rightPrepared = rightPath; |
|
|
|
rightPrepared = rightPath; |
|
|
|
} else if (isString(right)) { |
|
|
|
} else if (isString(right)) { |
|
|
|
rightPrepared = right.substring(1, right.length() - 1); |
|
|
|
rightPrepared = right.substring(1, right.length() - 1); |
|
|
|
|
|
|
|
} else if (isJson(right)) { |
|
|
|
|
|
|
|
rightPrepared = new JsonValue(right); |
|
|
|
} else if (isPattern(right)) { |
|
|
|
} else if (isPattern(right)) { |
|
|
|
rightPrepared = compilePattern(right); |
|
|
|
rightPrepared = compilePattern(right); |
|
|
|
} |
|
|
|
} |
|
|
@ -809,6 +842,42 @@ public class Criteria implements Predicate { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static int safeCompare(Object left, Object right) throws ValueCompareException { |
|
|
|
private static int safeCompare(Object left, Object right) throws ValueCompareException { |
|
|
|
|
|
|
|
return safeCompare(left, right, null); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static String unescape(String s) { |
|
|
|
|
|
|
|
if (s.indexOf(BS) == - 1) |
|
|
|
|
|
|
|
return s; |
|
|
|
|
|
|
|
StringBuilder sb = new StringBuilder(s.length()); |
|
|
|
|
|
|
|
for (int i = 0; i < s.length(); i++) { |
|
|
|
|
|
|
|
char c = s.charAt(i); |
|
|
|
|
|
|
|
if (c == BS) { |
|
|
|
|
|
|
|
char c2 = s.charAt(++i); |
|
|
|
|
|
|
|
switch (c2) { |
|
|
|
|
|
|
|
case 'b': c2 = '\b'; break; |
|
|
|
|
|
|
|
case 'f': c2 = '\f'; break; |
|
|
|
|
|
|
|
case 'n': c2 = '\n'; break; |
|
|
|
|
|
|
|
case 'r': c2 = '\r'; break; |
|
|
|
|
|
|
|
case 't': c2 = '\t'; break; |
|
|
|
|
|
|
|
case 'u': |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
String hex = s.substring(i + 1, i + 5); |
|
|
|
|
|
|
|
c2 = (char)Integer.parseInt(hex, 16); |
|
|
|
|
|
|
|
i += 4; |
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
|
|
|
|
|
throw new ValueCompareException("\\u parse failed", e); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
sb.append(c2); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
sb.append(c); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return sb.toString(); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static int safeCompare(Object left, Object right, PredicateContext ctx) throws ValueCompareException { |
|
|
|
|
|
|
|
|
|
|
|
if (left == right) { |
|
|
|
if (left == right) { |
|
|
|
return 0; |
|
|
|
return 0; |
|
|
@ -824,11 +893,8 @@ public class Criteria implements Predicate { |
|
|
|
} else if (leftNullish && rightNullish) { |
|
|
|
} else if (leftNullish && rightNullish) { |
|
|
|
return 0; |
|
|
|
return 0; |
|
|
|
} else if (left instanceof String && right instanceof String) { |
|
|
|
} else if (left instanceof String && right instanceof String) { |
|
|
|
String exp = (String) left; |
|
|
|
String expected = unescape((String) left); |
|
|
|
if (exp.contains("\'")) { |
|
|
|
return expected.compareTo((String) right); |
|
|
|
exp = exp.replace("\\'", "'"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return exp.compareTo((String) right); |
|
|
|
|
|
|
|
} else if (left instanceof Number && right instanceof Number) { |
|
|
|
} else if (left instanceof Number && right instanceof Number) { |
|
|
|
return new BigDecimal(left.toString()).compareTo(new BigDecimal(right.toString())); |
|
|
|
return new BigDecimal(left.toString()).compareTo(new BigDecimal(right.toString())); |
|
|
|
} else if (left instanceof String && right instanceof Number) { |
|
|
|
} else if (left instanceof String && right instanceof Number) { |
|
|
@ -841,6 +907,10 @@ public class Criteria implements Predicate { |
|
|
|
Boolean e = (Boolean) left; |
|
|
|
Boolean e = (Boolean) left; |
|
|
|
Boolean a = (Boolean) right; |
|
|
|
Boolean a = (Boolean) right; |
|
|
|
return e.compareTo(a); |
|
|
|
return e.compareTo(a); |
|
|
|
|
|
|
|
} else if (left instanceof JsonValue) { |
|
|
|
|
|
|
|
notNull(ctx, "ctx"); |
|
|
|
|
|
|
|
JsonValue json = (JsonValue) left; |
|
|
|
|
|
|
|
return right.equals(json.parsed(ctx)) ? 0 : -1; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
logger.debug("Can not compare a {} with a {}", left.getClass().getName(), right.getClass().getName()); |
|
|
|
logger.debug("Can not compare a {} with a {}", left.getClass().getName(), right.getClass().getName()); |
|
|
|
throw new ValueCompareException(); |
|
|
|
throw new ValueCompareException(); |
|
|
|