Browse Source

Allow a list to be compared to a regex in a filter. (#685)

Co-authored-by: Morgan Patch <morganpatch@pingidentity.com>
pull/797/merge
Morgan Patch 3 years ago committed by GitHub
parent
commit
3f4900d6e7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 27
      json-path/src/main/java/com/jayway/jsonpath/internal/filter/EvaluatorFactory.java
  2. 14
      json-path/src/test/java/com/jayway/jsonpath/FilterTest.java
  3. 47
      json-path/src/test/java/com/jayway/jsonpath/InlineFilterTest.java

27
json-path/src/main/java/com/jayway/jsonpath/internal/filter/EvaluatorFactory.java

@ -4,7 +4,9 @@ import com.jayway.jsonpath.JsonPathException;
import com.jayway.jsonpath.Predicate;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.regex.Pattern;
import static com.jayway.jsonpath.internal.filter.ValueNodes.PatternNode;
import static com.jayway.jsonpath.internal.filter.ValueNodes.ValueListNode;
@ -256,16 +258,41 @@ public class EvaluatorFactory {
}
if (left.isPatternNode()) {
if (right.isValueListNode() || (right.isJsonNode() && right.asJsonNode().isArray(ctx))) {
return matchesAny(left.asPatternNode(), right.asJsonNode().asValueListNode(ctx));
} else {
return matches(left.asPatternNode(), getInput(right));
}
} else {
if (left.isValueListNode() || (left.isJsonNode() && left.asJsonNode().isArray(ctx))) {
return matchesAny(right.asPatternNode(), left.asJsonNode().asValueListNode(ctx));
} else {
return matches(right.asPatternNode(), getInput(left));
}
}
}
private boolean matches(PatternNode patternNode, String inputToMatch) {
return patternNode.getCompiledPattern().matcher(inputToMatch).matches();
}
private boolean matchesAny(PatternNode patternNode, ValueNode valueNode) {
if (!valueNode.isValueListNode()) {
return false;
}
ValueListNode listNode = valueNode.asValueListNode();
Pattern pattern = patternNode.getCompiledPattern();
for (Iterator<ValueNode> it = listNode.iterator(); it.hasNext(); ) {
String input = getInput(it.next());
if (pattern.matcher(input).matches()) {
return true;
}
}
return false;
}
private String getInput(ValueNode valueNode) {
String input = "";

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

@ -28,7 +28,8 @@ public class FilterTest extends BaseTest {
" \"char-key\" : \"c\", " +
" \"arr-empty\" : [], " +
" \"int-arr\" : [0,1,2,3,4], " +
" \"string-arr\" : [\"a\",\"b\",\"c\",\"d\",\"e\"] " +
" \"string-arr\" : [\"a\",\"b\",\"c\",\"d\",\"e\"], " +
" \"obj\": {\"foo\": \"bar\"}" +
"}"
);
@ -263,6 +264,17 @@ public class FilterTest extends BaseTest {
assertThat(filter(where("int-key").regex(Pattern.compile("^string$"))).apply(createPredicateContext(json))).isEqualTo(false);
}
@Test
public void list_regex_evals() {
assertThat(filter(where("string-arr").regex(Pattern.compile("^d$"))).apply(createPredicateContext(json))).isEqualTo(true);
assertThat(filter(where("string-arr").regex(Pattern.compile("^q$"))).apply(createPredicateContext(json))).isEqualTo(false);
}
@Test
public void obj_regex_doesnt_break() {
assertThat(filter(where("obj").regex(Pattern.compile("^foo$"))).apply(createPredicateContext(json))).isEqualTo(false);
}
//----------------------------------------------------------------------------
//
// JSON equality

47
json-path/src/test/java/com/jayway/jsonpath/InlineFilterTest.java

@ -18,6 +18,47 @@ public class InlineFilterTest extends BaseTest {
private static int bookCount = 4;
public static final String MULTI_STORE_JSON_DOCUMENT = "{\n" +
" \"store\" : [{\n" +
" \"name\": \"First\"," +
" \"book\" : [\n" +
" {\n" +
" \"category\" : \"reference\",\n" +
" \"author\" : \"Nigel Rees\",\n" +
" \"title\" : \"Sayings of the Century\",\n" +
" \"display-price\" : 8.95\n" +
" },\n" +
" {\n" +
" \"category\" : \"fiction\",\n" +
" \"author\" : \"Evelyn Waugh\",\n" +
" \"title\" : \"Sword of Honour\",\n" +
" \"display-price\" : 12.99\n" +
" },\n" +
" {\n" +
" \"category\" : \"fiction\",\n" +
" \"author\" : \"Herman Melville\",\n" +
" \"title\" : \"Moby Dick\",\n" +
" \"isbn\" : \"0-553-21311-3\",\n" +
" \"display-price\" : 8.99\n" +
" },\n" +
" {\n" +
" \"category\" : \"fiction\",\n" +
" \"author\" : \"J. R. R. Tolkien\",\n" +
" \"title\" : \"The Lord of the Rings\",\n" +
" \"isbn\" : \"0-395-19395-8\",\n" +
" \"display-price\" : 22.99\n" +
" }]\n" +
" },\n" +
" {\n" +
" \"name\": \"Second\",\n" +
" \"book\": [\n" +
" {\n" +
" \"category\" : \"fiction\",\n" +
" \"author\" : \"Ernest Hemmingway\",\n" +
" \"title\" : \"The Old Man and the Sea\",\n" +
" \"display-price\" : 12.99\n" +
" }]\n" +
" }]}";
private Configuration conf = Configurations.GSON_CONFIGURATION;
@ -125,6 +166,12 @@ public class InlineFilterTest extends BaseTest {
assertThat(resLeft).containsExactly("Nigel Rees");
}
@Test
public void patterns_match_against_lists() {
List<String> haveRefBooks = JsonPath.parse(MULTI_STORE_JSON_DOCUMENT).read("$.store[?(@.book[*].category =~ /Reference/i)].name");
assertThat(haveRefBooks).containsExactly("First");
}
@Test
public void negate_exists_check() {
List<String> hasIsbn = JsonPath.parse(JSON_DOCUMENT).read("$.store.book[?(@.isbn)].author");

Loading…
Cancel
Save