Kalle Stenflo
10 years ago
13 changed files with 453 additions and 1299 deletions
@ -1,618 +0,0 @@ |
|||||||
package com.jayway.jsonpath; |
|
||||||
|
|
||||||
import com.jayway.jsonpath.internal.spi.compiler.PathCompiler; |
|
||||||
import com.jayway.jsonpath.spi.compiler.EvaluationContext; |
|
||||||
import com.jayway.jsonpath.spi.compiler.Path; |
|
||||||
import org.slf4j.Logger; |
|
||||||
import org.slf4j.LoggerFactory; |
|
||||||
|
|
||||||
import java.math.BigDecimal; |
|
||||||
import java.util.Arrays; |
|
||||||
import java.util.Collection; |
|
||||||
import java.util.LinkedList; |
|
||||||
import java.util.List; |
|
||||||
import java.util.regex.Pattern; |
|
||||||
|
|
||||||
import static com.jayway.jsonpath.internal.Utils.join; |
|
||||||
import static com.jayway.jsonpath.internal.Utils.notNull; |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* |
|
||||||
*/ |
|
||||||
public class Criteria2 implements Predicate { |
|
||||||
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(Criteria2.class); |
|
||||||
|
|
||||||
private final Path path; |
|
||||||
private CriteriaType criteriaType; |
|
||||||
private Object expected; |
|
||||||
|
|
||||||
private final List<Criteria2> criteriaChain; |
|
||||||
|
|
||||||
private enum CriteriaType { |
|
||||||
EQ { |
|
||||||
@Override |
|
||||||
boolean eval(Object expected, Object actual, Configuration configuration) { |
|
||||||
boolean res = (0 == safeCompare(expected, actual, configuration)); |
|
||||||
logger.debug("[{}] {} [{}] => {}", actual, name(), expected, res); |
|
||||||
return res; |
|
||||||
} |
|
||||||
}, |
|
||||||
NE { |
|
||||||
@Override |
|
||||||
boolean eval(Object expected, Object actual, Configuration configuration) { |
|
||||||
boolean res = (0 != safeCompare(expected, actual, configuration)); |
|
||||||
logger.debug("[{}] {} [{}] => {}", actual, name(), expected, res); |
|
||||||
return res; |
|
||||||
} |
|
||||||
}, |
|
||||||
GT { |
|
||||||
@Override |
|
||||||
boolean eval(Object expected, Object actual, Configuration configuration) { |
|
||||||
if ((expected == null) ^ (actual == null)) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
boolean res = (0 > safeCompare(expected, actual, configuration)); |
|
||||||
logger.debug("[{}] {} [{}] => {}", actual, name(), expected, res); |
|
||||||
return res; |
|
||||||
} |
|
||||||
}, |
|
||||||
GTE { |
|
||||||
@Override |
|
||||||
boolean eval(Object expected, Object actual, Configuration configuration) { |
|
||||||
if ((expected == null) ^ (actual == null)) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
boolean res = (0 >= safeCompare(expected, actual, configuration)); |
|
||||||
logger.debug("[{}] {} [{}] => {}", actual, name(), expected, res); |
|
||||||
return res; |
|
||||||
} |
|
||||||
}, |
|
||||||
LT { |
|
||||||
@Override |
|
||||||
boolean eval(Object expected, Object actual, Configuration configuration) { |
|
||||||
if ((expected == null) ^ (actual == null)) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
boolean res = (0 < safeCompare(expected, actual, configuration)); |
|
||||||
logger.debug("[{}] {} [{}] => {}", actual, name(), expected, res); |
|
||||||
return res; |
|
||||||
} |
|
||||||
}, |
|
||||||
LTE { |
|
||||||
@Override |
|
||||||
boolean eval(Object expected, Object actual, Configuration configuration) { |
|
||||||
if ((expected == null) ^ (actual == null)) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
boolean res = (0 <= safeCompare(expected, actual, configuration)); |
|
||||||
logger.debug("[{}] {} [{}] => {}", actual, name(), expected, res); |
|
||||||
return res; |
|
||||||
} |
|
||||||
}, |
|
||||||
IN { |
|
||||||
@Override |
|
||||||
boolean eval(Object expected, Object actual, Configuration configuration) { |
|
||||||
boolean res = false; |
|
||||||
Collection exps = (Collection) expected; |
|
||||||
for (Object exp : exps) { |
|
||||||
if (0 == safeCompare(exp, actual, configuration)) { |
|
||||||
res = true; |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
logger.debug("[{}] {} [{}] => {}", actual, name(), join(", ", exps), res); |
|
||||||
return res; |
|
||||||
} |
|
||||||
}, |
|
||||||
NIN { |
|
||||||
@Override |
|
||||||
boolean eval(Object expected, Object actual, Configuration configuration) { |
|
||||||
Collection nexps = (Collection) expected; |
|
||||||
boolean res = !nexps.contains(actual); |
|
||||||
logger.debug("[{}] {} [{}] => {}", actual, name(), join(", ", nexps), res); |
|
||||||
return res; |
|
||||||
} |
|
||||||
}, |
|
||||||
ALL { |
|
||||||
@Override |
|
||||||
boolean eval(Object expected, Object actual, Configuration configuration) { |
|
||||||
boolean res = true; |
|
||||||
Collection exps = (Collection) expected; |
|
||||||
if (configuration.getProvider().isArray(actual)) { |
|
||||||
for (Object exp : exps) { |
|
||||||
boolean found = false; |
|
||||||
for (Object check : configuration.getProvider().toIterable(actual)) { |
|
||||||
if (0 == safeCompare(exp, check, configuration)) { |
|
||||||
found = true; |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
if (!found) { |
|
||||||
res = false; |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
logger.debug("[{}] {} [{}] => {}", join(", ", configuration.getProvider().toIterable(actual)), name(), join(", ", exps), res); |
|
||||||
} else { |
|
||||||
res = false; |
|
||||||
logger.debug("[{}] {} [{}] => {}", "<NOT AN ARRAY>", name(), join(", ", exps), res); |
|
||||||
} |
|
||||||
return res; |
|
||||||
} |
|
||||||
}, |
|
||||||
SIZE { |
|
||||||
@Override |
|
||||||
boolean eval(Object expected, Object actual, Configuration configuration) { |
|
||||||
int size = (Integer) expected; |
|
||||||
boolean res; |
|
||||||
if (configuration.getProvider().isArray(actual)) { |
|
||||||
int length = configuration.getProvider().length(actual); |
|
||||||
res = length == size; |
|
||||||
logger.debug("Array with size {} {} {} => {}", length, name(), size, res); |
|
||||||
} else if (actual instanceof String) { |
|
||||||
int length = ((String) actual).length(); |
|
||||||
res = length == size; |
|
||||||
logger.debug("String with length {} {} {} => {}", length, name(), size, res); |
|
||||||
} else { |
|
||||||
res = false; |
|
||||||
logger.debug("{} {} {} => {}", actual == null ? "null" : actual.getClass().getName(), name(), size, res); |
|
||||||
} |
|
||||||
return res; |
|
||||||
} |
|
||||||
}, |
|
||||||
EXISTS { |
|
||||||
@Override |
|
||||||
boolean eval(Object expected, Object actual, Configuration configuration) { |
|
||||||
//This must be handled outside
|
|
||||||
throw new UnsupportedOperationException(); |
|
||||||
} |
|
||||||
}, |
|
||||||
TYPE { |
|
||||||
@Override |
|
||||||
boolean eval(Object expected, Object actual, Configuration configuration) { |
|
||||||
final Class<?> expType = (Class<?>) expected; |
|
||||||
final Class<?> actType = actual == null ? null : actual.getClass(); |
|
||||||
if (actType != null) { |
|
||||||
return expType.isAssignableFrom(actType); |
|
||||||
} |
|
||||||
return false; |
|
||||||
} |
|
||||||
}, |
|
||||||
REGEX { |
|
||||||
@Override |
|
||||||
boolean eval(Object expected, Object actual, Configuration configuration) { |
|
||||||
boolean res = false; |
|
||||||
final Pattern pattern = (Pattern) expected; |
|
||||||
if (actual != null && actual instanceof String) { |
|
||||||
res = pattern.matcher(actual.toString()).matches(); |
|
||||||
} |
|
||||||
logger.debug("[{}] {} [{}] => {}", actual, name(), expected.toString(), res); |
|
||||||
return res; |
|
||||||
} |
|
||||||
}, |
|
||||||
MATCHES { |
|
||||||
@Override |
|
||||||
boolean eval(Object expected, Object actual, Configuration configuration) { |
|
||||||
Predicate exp = (Predicate) expected; |
|
||||||
return exp.apply(actual, configuration); |
|
||||||
} |
|
||||||
}, |
|
||||||
NOT_EMPTY { |
|
||||||
@Override |
|
||||||
boolean eval(Object expected, Object actual, Configuration configuration) { |
|
||||||
boolean res = false; |
|
||||||
if (actual != null) { |
|
||||||
if (configuration.getProvider().isArray(actual)) { |
|
||||||
int len = configuration.getProvider().length(actual); |
|
||||||
res = (0 != len); |
|
||||||
logger.debug("array length = {} {} => {}", len, name(), res); |
|
||||||
} else if (actual instanceof String) { |
|
||||||
int len = ((String) actual).length(); |
|
||||||
res = (0 != len); |
|
||||||
logger.debug("string length = {} {} => {}", len, name(), res); |
|
||||||
} |
|
||||||
} |
|
||||||
return res; |
|
||||||
} |
|
||||||
}; |
|
||||||
|
|
||||||
abstract boolean eval(Object expected, Object actual, Configuration configuration); |
|
||||||
|
|
||||||
public static CriteriaType parse(String str) { |
|
||||||
if ("==".equals(str)) { |
|
||||||
return EQ; |
|
||||||
} else if (">".equals(str)) { |
|
||||||
return GT; |
|
||||||
} else if (">=".equals(str)) { |
|
||||||
return GTE; |
|
||||||
} else if ("<".equals(str)) { |
|
||||||
return LT; |
|
||||||
} else if ("<=".equals(str)) { |
|
||||||
return LTE; |
|
||||||
} else if ("!=".equals(str)) { |
|
||||||
return NE; |
|
||||||
} else { |
|
||||||
throw new UnsupportedOperationException("CriteriaType " + str + " can not be parsed"); |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
private Criteria2(List<Criteria2> criteriaChain, Path path) { |
|
||||||
if (!path.isDefinite()) { |
|
||||||
throw new InvalidCriteriaException("A criteria path must be definite. The path " + path.toString() + " is not!"); |
|
||||||
} |
|
||||||
this.path = path; |
|
||||||
this.criteriaChain = criteriaChain; |
|
||||||
this.criteriaChain.add(this); |
|
||||||
} |
|
||||||
|
|
||||||
private Criteria2(Path path) { |
|
||||||
this(new LinkedList<Criteria2>(), path); |
|
||||||
} |
|
||||||
|
|
||||||
private Criteria2(Path path, CriteriaType criteriaType, Object expected) { |
|
||||||
this(new LinkedList<Criteria2>(), path); |
|
||||||
this.criteriaType = criteriaType; |
|
||||||
this.expected = expected; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean apply(Object model, Configuration configuration) { |
|
||||||
for (Criteria2 criteria : criteriaChain) { |
|
||||||
if (!criteria.eval(model, configuration)) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
} |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
private boolean eval(Object model, Configuration configuration) { |
|
||||||
if (CriteriaType.EXISTS == criteriaType) { |
|
||||||
boolean exists = ((Boolean) expected); |
|
||||||
try { |
|
||||||
path.evaluate(model, configuration.options(Option.THROW_ON_MISSING_PROPERTY)).get(); |
|
||||||
return exists == true; |
|
||||||
} catch (PathNotFoundException e) { |
|
||||||
return exists == false; |
|
||||||
} |
|
||||||
} else { |
|
||||||
|
|
||||||
try { |
|
||||||
final Object actual = path.evaluate(model, configuration).get(); |
|
||||||
return criteriaType.eval(expected, actual, configuration); |
|
||||||
} catch (CompareException e) { |
|
||||||
return false; |
|
||||||
} catch (PathNotFoundException e) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Static factory method to create a Criteria using the provided key |
|
||||||
* |
|
||||||
* @param key filed name |
|
||||||
* @return the new criteria |
|
||||||
*/ |
|
||||||
public static Criteria2 where(Path key) { |
|
||||||
return new Criteria2(key); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Static factory method to create a Criteria using the provided key |
|
||||||
* |
|
||||||
* @param key filed name |
|
||||||
* @return the new criteria |
|
||||||
*/ |
|
||||||
|
|
||||||
public static Criteria2 where(String key) { |
|
||||||
return where(PathCompiler.tokenize(key)); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Static factory method to create a Criteria using the provided key |
|
||||||
* |
|
||||||
* @param key ads new filed to criteria |
|
||||||
* @return the criteria builder |
|
||||||
*/ |
|
||||||
public Criteria2 and(String key) { |
|
||||||
return new Criteria2(this.criteriaChain, PathCompiler.tokenize(key)); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Creates a criterion using equality |
|
||||||
* |
|
||||||
* @param o |
|
||||||
* @return |
|
||||||
*/ |
|
||||||
public Criteria2 is(Object o) { |
|
||||||
this.criteriaType = CriteriaType.TYPE.EQ; |
|
||||||
this.expected = o; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Creates a criterion using equality |
|
||||||
* |
|
||||||
* @param o |
|
||||||
* @return |
|
||||||
*/ |
|
||||||
public Criteria2 eq(Object o) { |
|
||||||
return is(o); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Creates a criterion using the <b>!=</b> operator |
|
||||||
* |
|
||||||
* @param o |
|
||||||
* @return |
|
||||||
*/ |
|
||||||
public Criteria2 ne(Object o) { |
|
||||||
this.criteriaType = CriteriaType.TYPE.NE; |
|
||||||
this.expected = o; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Creates a criterion using the <b><</b> operator |
|
||||||
* |
|
||||||
* @param o |
|
||||||
* @return |
|
||||||
*/ |
|
||||||
public Criteria2 lt(Object o) { |
|
||||||
this.criteriaType = CriteriaType.TYPE.LT; |
|
||||||
this.expected = o; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Creates a criterion using the <b><=</b> operator |
|
||||||
* |
|
||||||
* @param o |
|
||||||
* @return |
|
||||||
*/ |
|
||||||
public Criteria2 lte(Object o) { |
|
||||||
this.criteriaType = CriteriaType.TYPE.LTE; |
|
||||||
this.expected = o; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Creates a criterion using the <b>></b> operator |
|
||||||
* |
|
||||||
* @param o |
|
||||||
* @return |
|
||||||
*/ |
|
||||||
public Criteria2 gt(Object o) { |
|
||||||
this.criteriaType = CriteriaType.TYPE.GT; |
|
||||||
this.expected = o; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Creates a criterion using the <b>>=</b> operator |
|
||||||
* |
|
||||||
* @param o |
|
||||||
* @return |
|
||||||
*/ |
|
||||||
public Criteria2 gte(Object o) { |
|
||||||
this.criteriaType = CriteriaType.TYPE.GTE; |
|
||||||
this.expected = o; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* Creates a criterion using a Regex |
|
||||||
* |
|
||||||
* @param pattern |
|
||||||
* @return |
|
||||||
*/ |
|
||||||
public Criteria2 regex(Pattern pattern) { |
|
||||||
notNull(pattern, "pattern can not be null"); |
|
||||||
this.criteriaType = CriteriaType.TYPE.REGEX; |
|
||||||
this.expected = pattern; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* The <code>in</code> operator is analogous to the SQL IN modifier, allowing you |
|
||||||
* to specify an array of possible matches. |
|
||||||
* |
|
||||||
* @param o the values to match against |
|
||||||
* @return |
|
||||||
*/ |
|
||||||
public Criteria2 in(Object... o) { |
|
||||||
return in(Arrays.asList(o)); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* The <code>in</code> operator is analogous to the SQL IN modifier, allowing you |
|
||||||
* to specify an array of possible matches. |
|
||||||
* |
|
||||||
* @param c the collection containing the values to match against |
|
||||||
* @return |
|
||||||
*/ |
|
||||||
public Criteria2 in(Collection<?> c) { |
|
||||||
notNull(c, "collection can not be null"); |
|
||||||
this.criteriaType = CriteriaType.TYPE.IN; |
|
||||||
this.expected = c; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* The <code>nin</code> operator is similar to $in except that it selects objects for |
|
||||||
* which the specified field does not have any value in the specified array. |
|
||||||
* |
|
||||||
* @param o the values to match against |
|
||||||
* @return |
|
||||||
*/ |
|
||||||
public Criteria2 nin(Object... o) { |
|
||||||
return nin(Arrays.asList(o)); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* The <code>nin</code> operator is similar to $in except that it selects objects for |
|
||||||
* which the specified field does not have any value in the specified array. |
|
||||||
* |
|
||||||
* @param c the values to match against |
|
||||||
* @return |
|
||||||
*/ |
|
||||||
public Criteria2 nin(Collection<?> c) { |
|
||||||
notNull(c, "collection can not be null"); |
|
||||||
this.criteriaType = CriteriaType.TYPE.NIN; |
|
||||||
this.expected = c; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* The <code>all</code> operator is similar to $in, but instead of matching any value |
|
||||||
* in the specified array all values in the array must be matched. |
|
||||||
* |
|
||||||
* @param o |
|
||||||
* @return |
|
||||||
*/ |
|
||||||
public Criteria2 all(Object... o) { |
|
||||||
return all(Arrays.asList(o)); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* The <code>all</code> operator is similar to $in, but instead of matching any value |
|
||||||
* in the specified array all values in the array must be matched. |
|
||||||
* |
|
||||||
* @param c |
|
||||||
* @return |
|
||||||
*/ |
|
||||||
public Criteria2 all(Collection<?> c) { |
|
||||||
notNull(c, "collection can not be null"); |
|
||||||
this.criteriaType = CriteriaType.TYPE.ALL; |
|
||||||
this.expected = c; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* The <code>size</code> operator matches: |
|
||||||
* <p/> |
|
||||||
* <ol> |
|
||||||
* <li>array with the specified number of elements.</li> |
|
||||||
* <li>string with given length.</li> |
|
||||||
* </ol> |
|
||||||
* |
|
||||||
* @param size |
|
||||||
* @return |
|
||||||
*/ |
|
||||||
public Criteria2 size(int size) { |
|
||||||
this.criteriaType = CriteriaType.TYPE.SIZE; |
|
||||||
this.expected = size; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
/** |
|
||||||
* Check for existence (or lack thereof) of a field. |
|
||||||
* |
|
||||||
* @param b |
|
||||||
* @return |
|
||||||
*/ |
|
||||||
public Criteria2 exists(boolean b) { |
|
||||||
this.criteriaType = CriteriaType.TYPE.EXISTS; |
|
||||||
this.expected = b; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* The $type operator matches values based on their Java type. |
|
||||||
* |
|
||||||
* @param t |
|
||||||
* @return |
|
||||||
*/ |
|
||||||
public Criteria2 type(Class<?> t) { |
|
||||||
notNull(t, "type can not be null"); |
|
||||||
this.criteriaType = CriteriaType.TYPE.TYPE; |
|
||||||
this.expected = t; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* The <code>notEmpty</code> operator checks that an array or String is not empty. |
|
||||||
* |
|
||||||
* @return |
|
||||||
*/ |
|
||||||
public Criteria2 notEmpty() { |
|
||||||
this.criteriaType = CriteriaType.TYPE.NOT_EMPTY; |
|
||||||
this.expected = null; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
/** |
|
||||||
* The <code>matches</code> operator checks that an object matches the given predicate. |
|
||||||
* |
|
||||||
* @return |
|
||||||
*/ |
|
||||||
public Criteria2 matches(Predicate p) { |
|
||||||
this.criteriaType = CriteriaType.TYPE.MATCHES; |
|
||||||
this.expected = p; |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
private static int safeCompare(Object expected, Object actual, Configuration configuration) { |
|
||||||
if (expected == null && actual != null) { |
|
||||||
return -1; |
|
||||||
} else if (expected != null && actual == null) { |
|
||||||
return 1; |
|
||||||
} else if (expected == null && actual == null) { |
|
||||||
return 0; |
|
||||||
} else if (expected instanceof String && actual instanceof String) { |
|
||||||
return ((String) expected).compareTo((String) actual); |
|
||||||
} else if (expected instanceof Number && actual instanceof Number) { |
|
||||||
return new BigDecimal(expected.toString()).compareTo(new BigDecimal(actual.toString())); |
|
||||||
} else if (expected instanceof String && actual instanceof Number) { |
|
||||||
return new BigDecimal(expected.toString()).compareTo(new BigDecimal(actual.toString())); |
|
||||||
} else if (expected instanceof String && actual instanceof Boolean) { |
|
||||||
Boolean e = Boolean.valueOf((String)expected); |
|
||||||
Boolean a = (Boolean) actual; |
|
||||||
return e.compareTo(a); |
|
||||||
} else if (expected instanceof Boolean && actual instanceof Boolean) { |
|
||||||
Boolean e = (Boolean) expected; |
|
||||||
Boolean a = (Boolean) actual; |
|
||||||
return e.compareTo(a); |
|
||||||
} else { |
|
||||||
logger.debug("Can not compare a {} with a {}", expected.getClass().getName(), actual.getClass().getName()); |
|
||||||
throw new CompareException(); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
private static class CompareException extends RuntimeException { |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
public static Criteria2 create(String path, String operator, String expected) { |
|
||||||
if (expected.startsWith("'") && expected.endsWith("'")) { |
|
||||||
expected = expected.substring(1, expected.length() - 1); |
|
||||||
} |
|
||||||
|
|
||||||
Path p = PathCompiler.tokenize(path); |
|
||||||
|
|
||||||
if (operator.isEmpty()) { |
|
||||||
return Criteria2.where(path).exists(true); |
|
||||||
} else { |
|
||||||
return new Criteria2(p, CriteriaType.parse(operator), expected); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public String toString() { |
|
||||||
StringBuilder sb = new StringBuilder(); |
|
||||||
sb.append(path.toString()) |
|
||||||
.append("|") |
|
||||||
.append(criteriaType.name()) |
|
||||||
.append("|") |
|
||||||
.append(expected) |
|
||||||
.append("|"); |
|
||||||
return sb.toString(); |
|
||||||
} |
|
||||||
} |
|
@ -1,170 +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; |
package com.jayway.jsonpath; |
||||||
|
|
||||||
import com.jayway.jsonpath.spi.json.JsonProvider; |
import java.util.ArrayList; |
||||||
|
import java.util.List; |
||||||
import java.util.HashMap; |
|
||||||
import java.util.Iterator; |
|
||||||
import java.util.LinkedHashMap; |
|
||||||
|
|
||||||
/** |
/** |
||||||
* A filter is used to filter the content of a JSON array in a JSONPath. |
|
||||||
* <p/> |
|
||||||
* Sample |
|
||||||
* <p/> |
|
||||||
* <code> |
|
||||||
* String doc = {"items": [{"name" : "john"}, {"name": "bob"}]} |
|
||||||
* <p/> |
|
||||||
* List<String> names = JsonPath.read(doc, "$items[?].name", Filter.filter(Criteria.where("name").is("john")); |
|
||||||
* </code> |
|
||||||
* |
* |
||||||
* @author Kalle Stenflo |
|
||||||
* @see Criteria |
|
||||||
*/ |
*/ |
||||||
public abstract class Filter<T> { |
public class Filter implements Predicate { |
||||||
|
|
||||||
/** |
private List<Criteria> criteriaList = new ArrayList<Criteria>(); |
||||||
* Creates a new filter based on given criteria |
|
||||||
* |
|
||||||
* @param criteria the filter criteria |
|
||||||
* @return a new filter |
|
||||||
*/ |
|
||||||
public static Filter filter(Criteria criteria) { |
|
||||||
return new MapFilter(criteria); |
|
||||||
} |
|
||||||
|
|
||||||
/** |
private Filter(Criteria criteria) { |
||||||
* Filters the provided list based on this filter configuration |
this.criteriaList.add(criteria); |
||||||
* |
|
||||||
* @param filterItems items to filter |
|
||||||
* @param configuration the json provider configuration that is used to create the result list |
|
||||||
* @return the filtered list |
|
||||||
*/ |
|
||||||
public Object doFilter(Iterable<T> filterItems, Configuration configuration) { |
|
||||||
JsonProvider provider = configuration.getProvider(); |
|
||||||
Object result = provider.createArray(); |
|
||||||
for (T filterItem : filterItems) { |
|
||||||
if (accept(filterItem, configuration)) { |
|
||||||
provider.setProperty(result, provider.length(result), filterItem); |
|
||||||
} |
|
||||||
} |
|
||||||
return result; |
|
||||||
} |
} |
||||||
|
|
||||||
/** |
private Filter(List<Criteria> criteriaList) { |
||||||
* Check if this filter will accept or reject the given object |
this.criteriaList = criteriaList; |
||||||
* |
|
||||||
* @param obj item to check |
|
||||||
* @return true if filter matches |
|
||||||
*/ |
|
||||||
public abstract boolean accept(T obj); |
|
||||||
|
|
||||||
/** |
|
||||||
* Check if this filter will accept or reject the given object |
|
||||||
* |
|
||||||
* @param obj item to check |
|
||||||
* @param configuration |
|
||||||
* @return true if filter matches |
|
||||||
*/ |
|
||||||
public abstract boolean accept(T obj, Configuration configuration); |
|
||||||
|
|
||||||
/** |
|
||||||
* Adds a new criteria to this filter |
|
||||||
* |
|
||||||
* @param criteria to add |
|
||||||
* @return the updated filter |
|
||||||
*/ |
|
||||||
public abstract Filter addCriteria(Criteria criteria); |
|
||||||
|
|
||||||
|
|
||||||
// --------------------------------------------------------
|
|
||||||
//
|
|
||||||
// Default filter implementation
|
|
||||||
//
|
|
||||||
// --------------------------------------------------------
|
|
||||||
public static abstract class FilterAdapter<T> extends Filter<T> { |
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean accept(T obj) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean accept(T obj, Configuration configuration) { |
|
||||||
return accept(obj); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public Filter addCriteria(Criteria criteria) { |
|
||||||
throw new UnsupportedOperationException("can not add criteria to a FilterAdapter."); |
|
||||||
} |
|
||||||
|
|
||||||
} |
} |
||||||
|
|
||||||
private static class MapFilter extends FilterAdapter<Object> { |
public static Filter filter(Criteria criteria) { |
||||||
|
return new Filter(criteria); |
||||||
private HashMap<String, Criteria> criteria = new LinkedHashMap<String, Criteria>(); |
} |
||||||
|
|
||||||
public MapFilter(Criteria criteria) { |
|
||||||
addCriteria(criteria); |
|
||||||
} |
|
||||||
|
|
||||||
public MapFilter addCriteria(Criteria criteria) { |
|
||||||
String key = criteria.getKey().toString(); |
|
||||||
Criteria existing = this.criteria.get(key); |
|
||||||
if (existing == null) { |
|
||||||
this.criteria.put(key, criteria); |
|
||||||
} else { |
|
||||||
existing.andOperator(criteria); |
|
||||||
} |
|
||||||
return this; |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
public static Filter filter(List<Criteria> criteriaList) { |
||||||
public boolean accept(Object map) { |
return new Filter(criteriaList); |
||||||
return accept(map, Configuration.defaultConfiguration()); |
} |
||||||
} |
|
||||||
|
|
||||||
@Override |
@Override |
||||||
public boolean accept(Object map, Configuration configuration) { |
public boolean apply(Object target, Configuration configuration) { |
||||||
for (Criteria criterion : this.criteria.values()) { |
for (Criteria criteria : criteriaList) { |
||||||
if (!criterion.matches(map, configuration)) { |
if (!criteria.apply(target, configuration)) { |
||||||
return false; |
return false; |
||||||
} |
|
||||||
} |
} |
||||||
return true; |
|
||||||
} |
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
@Override |
public void addCriteria(Criteria criteria) { |
||||||
public String toString() { |
criteriaList.add(criteria); |
||||||
StringBuilder sb = new StringBuilder(); |
} |
||||||
sb.append("[?("); |
|
||||||
|
|
||||||
Iterator<Criteria> criteriaIterator = criteria.values().iterator(); |
|
||||||
Criteria criterion = criteriaIterator.next(); |
|
||||||
sb.append(criterion.toString()); |
|
||||||
|
|
||||||
while (criteriaIterator.hasNext()) { |
|
||||||
sb.append(" && ") |
|
||||||
.append(criteriaIterator.next().toString()); |
|
||||||
} |
|
||||||
sb.append(")]"); |
|
||||||
|
|
||||||
return sb.toString(); |
@Override |
||||||
|
public String toString() { |
||||||
|
StringBuilder sb = new StringBuilder(); |
||||||
|
for (Criteria crit : criteriaList) { |
||||||
|
sb.append(crit.toString()); |
||||||
} |
} |
||||||
|
return sb.toString(); |
||||||
} |
} |
||||||
} |
} |
||||||
|
@ -1,54 +0,0 @@ |
|||||||
package com.jayway.jsonpath; |
|
||||||
|
|
||||||
import java.util.ArrayList; |
|
||||||
import java.util.List; |
|
||||||
|
|
||||||
import static java.util.Arrays.asList; |
|
||||||
|
|
||||||
/** |
|
||||||
* |
|
||||||
*/ |
|
||||||
public class Filter2 implements Predicate { |
|
||||||
|
|
||||||
private List<Criteria2> criteriaList = new ArrayList<Criteria2>(); |
|
||||||
|
|
||||||
private Filter2(Criteria2 criteria) { |
|
||||||
this.criteriaList.add(criteria); |
|
||||||
} |
|
||||||
|
|
||||||
private Filter2(List<Criteria2> criteriaList) { |
|
||||||
this.criteriaList = criteriaList; |
|
||||||
} |
|
||||||
|
|
||||||
public static Filter2 filter(Criteria2 criteria) { |
|
||||||
return new Filter2(criteria); |
|
||||||
} |
|
||||||
|
|
||||||
public static Filter2 filter(List<Criteria2> criteriaList) { |
|
||||||
return new Filter2(criteriaList); |
|
||||||
} |
|
||||||
|
|
||||||
@Override |
|
||||||
public boolean apply(Object target, Configuration configuration) { |
|
||||||
for (Criteria2 criteria : criteriaList) { |
|
||||||
if (!criteria.apply(target, configuration)) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
} |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
public void addCriteria(Criteria2 criteria) { |
|
||||||
criteriaList.add(criteria); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
@Override |
|
||||||
public String toString() { |
|
||||||
StringBuilder sb = new StringBuilder(); |
|
||||||
for (Criteria2 crit : criteriaList) { |
|
||||||
sb.append(crit.toString()); |
|
||||||
} |
|
||||||
return sb.toString(); |
|
||||||
} |
|
||||||
} |
|
Loading…
Reference in new issue