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" + " \"bicycle\": {\n" +
" \"color\": \"red\",\n" + " \"color\": \"red\",\n" +
" \"price\": 19.95\n," + " \"price\": 19.95\n," +
" \"gears\": [23, 50]\n," +
" \"extra\": {\"x\": 0}\n," +
" \"nullValue\": null\n" + " \"nullValue\": null\n" +
" }\n" + " }\n" +
" }\n" + " }\n" +
@ -55,6 +57,13 @@ public class JsonAssertTest {
with(JSON).assertNotDefined("$.store.bicycle[?(@.color == 'red' )]"); 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) @Test(expected = AssertionError.class)
public void failed_error_message() throws Exception { 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.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;
@ -59,7 +60,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 +73,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 +711,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 +736,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 +763,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 +827,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 +841,10 @@ 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 int safeCompare(Object left, Object right, PredicateContext ctx) throws ValueCompareException {
if (left == right) { if (left == right) {
return 0; return 0;
@ -841,6 +877,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();

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); 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 // IN

Loading…
Cancel
Save