/*
 * 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.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<Criteria> criteriaChain;
    private ValueNode left;
    private RelationalOperator criteriaType;
    private ValueNode right;

    private Criteria(List<Criteria> criteriaChain, ValueNode left) {
        this.left = left;
        this.criteriaChain = criteriaChain;
        this.criteriaChain.add(this);
    }

    private Criteria(ValueNode left) {
        this(new LinkedList<Criteria>(), 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<RelationalExpressionNode> toRelationalExpressionNodes(){
        List<RelationalExpressionNode> nodes = new ArrayList<RelationalExpressionNode>(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
Params:
  • key – filed name
Returns:the new criteria
/** * 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(ValueNode.createPathNode(key)); }
Static factory method to create a Criteria using the provided key
Params:
  • key – filed name
Returns:the new criteria
/** * 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
Params:
  • key – ads new filed to criteria
Returns:the criteria builder
/** * 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
Params:
  • o –
Returns:the criteria
/** * 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
Params:
  • o –
Returns:the criteria
/** * Creates a criterion using equality * * @param o * @return the criteria */
public Criteria eq(Object o) { return is(o); }
Creates a criterion using the != operator
Params:
  • o –
Returns:the criteria
/** * Creates a criterion using the <b>!=</b> 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
Params:
  • o –
Returns:the criteria
/** * Creates a criterion using the <b>&lt;</b> 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
Params:
  • o –
Returns:the criteria
/** * Creates a criterion using the <b>&lt;=</b> 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
Params:
  • o –
Returns:the criteria
/** * Creates a criterion using the <b>&gt;</b> 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
Params:
  • o –
Returns:the criteria
/** * Creates a criterion using the <b>&gt;=</b> 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
Params:
  • pattern –
Returns:the criteria
/** * 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.
Params:
  • o – the values to match against
Returns:the criteria
/** * 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 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.
Params:
  • c – the collection containing the values to match against
Returns:the criteria
/** * 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 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.
Params:
  • o – that should exists in given collection or
Returns:the criteria
/** * The <code>contains</code> 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.
Params:
  • o – the values to match against
Returns:the criteria
/** * 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 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.
Params:
  • c – the values to match against
Returns:the criteria
/** * 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 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 subsetof operator selects objects for which the specified field is an array whose elements comprise a subset of the set comprised by the elements of the specified array.
Params:
  • o – the values to match against
Returns:the criteria
/** * The <code>subsetof</code> operator selects objects for which the specified field is * an array whose elements comprise a subset of the set comprised by the elements of * the specified array. * * @param o the values to match against * @return the criteria */
public Criteria subsetof(Object... o) { return subsetof(Arrays.asList(o)); }
The subsetof operator selects objects for which the specified field is an array whose elements comprise a subset of the set comprised by the elements of the specified array.
Params:
  • c – the values to match against
Returns:the criteria
/** * The <code>subsetof</code> operator selects objects for which the specified field is * an array whose elements comprise a subset of the set comprised by the elements of * the specified array. * * @param c the values to match against * @return the criteria */
public Criteria subsetof(Collection<?> c) { notNull(c, "collection can not be null"); this.criteriaType = RelationalOperator.SUBSETOF; 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.
Params:
  • o –
Returns:the criteria
/** * 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 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.
Params:
  • c –
Returns:the criteria
/** * 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 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. string with given length.
Params:
  • size –
Returns:the criteria
/** * 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 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
Params:
  • clazz –
Returns:the criteria
/** * 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.
Params:
  • shouldExist –
Returns:the criteria
/** * 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.
Returns:the criteria
/** * The <code>notEmpty</code> 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.
Params:
  • empty – should be empty
Returns:the criteria
/** * The <code>notEmpty</code> 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.
Params:
  • p –
Returns:the criteria
/** * The <code>matches</code> 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 Filter.parse(String)
Params:
  • criteria –
Returns:a criteria
/** * Parse the provided criteria * * Deprecated use {@link Filter#parse(String)} * * @param criteria * @return a criteria */
@Deprecated public static Criteria parse(String criteria) { if(criteria == null){ throw new InvalidPathException("Criteria can not be null"); } String[] split = criteria.trim().split(" "); if(split.length == 3){ return create(split[0], split[1], split[2]); } else if(split.length == 1){ return create(split[0], "EXISTS", "true"); } else { throw new InvalidPathException("Could not parse criteria"); } }
Creates a new criteria
Params:
  • left – path to evaluate in criteria
  • operator – operator
  • right – expected value
Returns:a new Criteria
/** * Creates a new criteria * @param left path to evaluate in criteria * @param operator operator * @param right expected value * @return a new Criteria */
@Deprecated public static Criteria create(String left, String operator, String right) { Criteria criteria = new Criteria(ValueNode.toValueNode(left)); criteria.criteriaType = RelationalOperator.fromString(operator); criteria.right = ValueNode.toValueNode(right); return criteria; } 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."); } } }