/* * 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; import com.jayway.jsonpath.internal.Path; import com.jayway.jsonpath.internal.Utils; import com.jayway.jsonpath.internal.filter.PathNode; import com.jayway.jsonpath.internal.filter.RelationalExpressionNode; import com.jayway.jsonpath.internal.filter.RelationalOperator; import com.jayway.jsonpath.internal.filter.ValueNode; import java.util.ArrayList; 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.notNull; /** * */ @SuppressWarnings("unchecked") public class Criteria implements Predicate { private final List criteriaChain; private ValueNode left; private RelationalOperator criteriaType; private ValueNode right; private Criteria(List criteriaChain, ValueNode left) { this.left = left; this.criteriaChain = criteriaChain; this.criteriaChain.add(this); } private Criteria(ValueNode left) { this(new LinkedList(), left); } @Override public boolean apply(PredicateContext ctx) { for (RelationalExpressionNode expressionNode : toRelationalExpressionNodes()) { if(!expressionNode.apply(ctx)){ return false; } } return true; } @Override public String toString() { return Utils.join(" && ", toRelationalExpressionNodes()); } private Collection toRelationalExpressionNodes(){ List nodes = new ArrayList(criteriaChain.size()); for (Criteria criteria : criteriaChain) { nodes.add(new RelationalExpressionNode(criteria.left, criteria.criteriaType, criteria.right)); } return nodes; } /** * Static factory method to create a Criteria using the provided key * * @param key filed name * @return the new criteria */ @Deprecated //This should be private.It exposes internal classes public static Criteria where(Path key) { return new Criteria(new PathNode(key)); } /** * Static factory method to create a Criteria using the provided key * * @param key filed name * @return the new criteria */ public static Criteria where(String key) { return new Criteria(ValueNode.toValueNode(prefixPath(key))); } /** * Static factory method to create a Criteria using the provided key * * @param key ads new filed to criteria * @return the criteria builder */ public Criteria and(String key) { checkComplete(); return new Criteria(this.criteriaChain, ValueNode.toValueNode(prefixPath(key))); } /** * Creates a criterion using equality * * @param o * @return the criteria */ public Criteria is(Object o) { this.criteriaType = RelationalOperator.EQ; this.right = ValueNode.toValueNode(o); return this; } /** * Creates a criterion using equality * * @param o * @return the criteria */ public Criteria eq(Object o) { return is(o); } /** * Creates a criterion using the != operator * * @param o * @return the criteria */ public Criteria ne(Object o) { this.criteriaType = RelationalOperator.NE; this.right = ValueNode.toValueNode(o); return this; } /** * Creates a criterion using the < operator * * @param o * @return the criteria */ public Criteria lt(Object o) { this.criteriaType = RelationalOperator.LT; this.right = ValueNode.toValueNode(o); return this; } /** * Creates a criterion using the <= operator * * @param o * @return the criteria */ public Criteria lte(Object o) { this.criteriaType = RelationalOperator.LTE; this.right = ValueNode.toValueNode(o); return this; } /** * Creates a criterion using the > operator * * @param o * @return the criteria */ public Criteria gt(Object o) { this.criteriaType = RelationalOperator.GT; this.right = ValueNode.toValueNode(o); return this; } /** * Creates a criterion using the >= operator * * @param o * @return the criteria */ public Criteria gte(Object o) { this.criteriaType = RelationalOperator.GTE; this.right = ValueNode.toValueNode(o); return this; } /** * Creates a criterion using a Regex * * @param pattern * @return the criteria */ public Criteria regex(Pattern pattern) { notNull(pattern, "pattern can not be null"); this.criteriaType = RelationalOperator.REGEX; this.right = ValueNode.toValueNode(pattern); return this; } /** * The in 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 the criteria */ public Criteria in(Object... o) { return in(Arrays.asList(o)); } /** * The in 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 the criteria */ public Criteria in(Collection c) { notNull(c, "collection can not be null"); this.criteriaType = RelationalOperator.IN; this.right = new ValueNode.ValueListNode(c); return this; } /** * The contains operator asserts that the provided object is contained * in the result. The object that should contain the input can be either an object or a String. * * @param o that should exists in given collection or * @return the criteria */ public Criteria contains(Object o) { this.criteriaType = RelationalOperator.CONTAINS; this.right = ValueNode.toValueNode(o); return this; } /** * The nin 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 the criteria */ public Criteria nin(Object... o) { return nin(Arrays.asList(o)); } /** * The nin 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 the criteria */ public Criteria nin(Collection c) { notNull(c, "collection can not be null"); this.criteriaType = RelationalOperator.NIN; this.right = new ValueNode.ValueListNode(c); return this; } /** * The all 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 the criteria */ public Criteria all(Object... o) { return all(Arrays.asList(o)); } /** * The all 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 the criteria */ public Criteria all(Collection c) { notNull(c, "collection can not be null"); this.criteriaType = RelationalOperator.ALL; this.right = new ValueNode.ValueListNode(c); return this; } /** * The size operator matches: *

*

    *
  1. array with the specified number of elements.
  2. *
  3. string with given length.
  4. *
* * @param size * @return the criteria */ public Criteria size(int size) { this.criteriaType = RelationalOperator.SIZE; this.right = ValueNode.toValueNode(size); return this; } /** * The $type operator matches values based on their Java JSON type. * * Supported types are: * * List.class * Map.class * String.class * Number.class * Boolean.class * * Other types evaluates to false * * @param clazz * @return the criteria */ public Criteria type(Class clazz) { this.criteriaType = RelationalOperator.TYPE; this.right = ValueNode.createClassNode(clazz); return this; } /** * Check for existence (or lack thereof) of a field. * * @param shouldExist * @return the criteria */ public Criteria exists(boolean shouldExist) { this.criteriaType = RelationalOperator.EXISTS; this.right = ValueNode.toValueNode(shouldExist); this.left = left.asPathNode().asExistsCheck(shouldExist); return this; } /** * The notEmpty operator checks that an array or String is not empty. * * @return the criteria */ @Deprecated public Criteria notEmpty() { return empty(false); } /** * The notEmpty operator checks that an array or String is empty. * * @param empty should be empty * @return the criteria */ public Criteria empty(boolean empty) { this.criteriaType = RelationalOperator.EMPTY; this.right = empty ? ValueNode.TRUE : ValueNode.FALSE; return this; } /** * The matches operator checks that an object matches the given predicate. * * @param p * @return the criteria */ public Criteria matches(Predicate p) { this.criteriaType = RelationalOperator.MATCHES; this.right = new ValueNode.PredicateNode(p); return this; } /** * Parse the provided criteria * * Deprecated use {@link Filter#parse(String)} * * @param criteria * @return a criteria */ @Deprecated public static Criteria parse(String criteria) { //TODO: fix return null; } private static String prefixPath(String key){ if (!key.startsWith("$") && !key.startsWith("@")) { key = "@." + key; } return key; } private void checkComplete(){ boolean complete = (left != null && criteriaType != null && right != null); if(!complete){ throw new JsonPathException("Criteria build exception. Complete on criteria before defining next."); } } }