Browse Source

Allow JSON values to be directly used in criteria matching

This is useful for matching against arrays of primitives, for example.
pull/115/head
Elias Ross 9 years ago
parent
commit
c759a20188
  1. 9
      json-path-assert/src/test/java/com/jayway/jsonassert/JsonAssertTest.java
  2. 46
      json-path/src/main/java/com/jayway/jsonpath/Criteria.java
  3. 20
      json-path/src/test/java/com/jayway/jsonpath/FilterTest.java

9
json-path-assert/src/test/java/com/jayway/jsonassert/JsonAssertTest.java

@ -38,6 +38,8 @@ public class JsonAssertTest {
" \"bicycle\": {\n" +
" \"color\": \"red\",\n" +
" \"price\": 19.95\n," +
" \"gears\": [23, 50]\n," +
" \"extra\": {\"x\": 0}\n," +
" \"nullValue\": null\n" +
" }\n" +
" }\n" +
@ -55,6 +57,13 @@ public class JsonAssertTest {
with(JSON).assertNotDefined("$.store.bicycle[?(@.color == 'red' )]");
}
@Test
public void assert_gears() throws Exception {
with(JSON).assertThat("$.store.bicycle[?(@.gears == [23, 50])]", is(collectionWithSize(equalTo(1))));
with(JSON).assertThat("$.store.bicycle[?(@.gears == [23, 77])]", is(collectionWithSize(equalTo(0))));
with(JSON).assertThat("$.store.bicycle[?(@.extra == {\"x\":0})]", is(collectionWithSize(equalTo(1))));
}
@Test(expected = AssertionError.class)
public void failed_error_message() throws Exception {

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

@ -17,6 +17,7 @@ package com.jayway.jsonpath;
import com.jayway.jsonpath.internal.Path;
import com.jayway.jsonpath.internal.PathCompiler;
import com.jayway.jsonpath.internal.token.PredicateContextImpl;
import com.jayway.jsonpath.spi.json.JsonProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -59,7 +60,7 @@ public class Criteria implements Predicate {
EQ {
@Override
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);
return res;
}
@ -72,7 +73,7 @@ public class Criteria implements Predicate {
NE {
@Override
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);
return res;
}
@ -710,6 +711,14 @@ public class Criteria implements Predicate {
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) {
return (string != null
&& !string.isEmpty()
@ -727,7 +736,6 @@ public class Criteria implements Predicate {
return Pattern.compile(regex, flags);
}
/**
* Parse the provided criteria
*
@ -755,6 +763,28 @@ public class Criteria implements Predicate {
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
*
@ -797,6 +827,8 @@ public class Criteria implements Predicate {
rightPrepared = rightPath;
} else if (isString(right)) {
rightPrepared = right.substring(1, right.length() - 1);
} else if (isJson(right)) {
rightPrepared = new JsonValue(right);
} else if (isPattern(right)) {
rightPrepared = compilePattern(right);
}
@ -809,6 +841,10 @@ public class Criteria implements Predicate {
}
private static int safeCompare(Object left, Object right) throws ValueCompareException {
return safeCompare(left, right, null);
}
private static int safeCompare(Object left, Object right, PredicateContext ctx) throws ValueCompareException {
if (left == right) {
return 0;
@ -841,6 +877,10 @@ public class Criteria implements Predicate {
Boolean e = (Boolean) left;
Boolean a = (Boolean) right;
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 {
logger.debug("Can not compare a {} with a {}", left.getClass().getName(), right.getClass().getName());
throw new ValueCompareException();

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

@ -240,6 +240,26 @@ public class FilterTest extends BaseTest {
assertThat(filter(where("int-key").regex(Pattern.compile("^string$"))).apply(createPredicateContext(json))).isEqualTo(false);
}
//----------------------------------------------------------------------------
//
// JSON equality
//
//----------------------------------------------------------------------------
@Test
public void json_evals() {
String nest = "{\"a\":true}";
String arr = "[1,2]";
String json = "{\"foo\":" + arr + ", \"bar\":" + nest + "}";
Object tree = Configuration.defaultConfiguration().jsonProvider().parse(json);
Predicate.PredicateContext context = createPredicateContext(tree);
Filter farr = Filter.parse("[?(@.foo == " + arr + ")]");
Filter fobjF = Filter.parse("[?(@.foo == " + nest + ")]");
Filter fobjT = Filter.parse("[?(@.bar == " + nest + ")]");
assertThat(farr.apply(context)).isEqualTo(true);
assertThat(fobjF.apply(context)).isEqualTo(false);
assertThat(fobjT.apply(context)).isEqualTo(true);
}
//----------------------------------------------------------------------------
//
// IN

Loading…
Cancel
Save