From 410e4269c7c87de409b14cdbcc5418f2b79f1ff1 Mon Sep 17 00:00:00 2001 From: Kalle Stenflo Date: Thu, 22 Aug 2013 10:31:17 +0200 Subject: [PATCH] Support null filters like [?(@foo == null)] and [?(@foo != null)] --- .../filter/eval/ExpressionEvaluator.java | 28 ++++++- .../jayway/jsonpath/ExpressionEvalTest.java | 84 ++++++++++++++++++- 2 files changed, 108 insertions(+), 4 deletions(-) diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/eval/ExpressionEvaluator.java b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/eval/ExpressionEvaluator.java index 26723362..6e1097b5 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/filter/eval/ExpressionEvaluator.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/filter/eval/ExpressionEvaluator.java @@ -25,9 +25,16 @@ import java.util.Map; */ public class ExpressionEvaluator { + private static final String NULL_VALUE = "null"; public enum Operator { - equal("=="), not_equal("!="), less_or_greater_than("<>"), greater_than(">"), greater_than_or_equal(">="), less_than("<"), less_than_or_equal("<="); + equal("=="), + not_equal("!="), + less_or_greater_than("<>"), //same as not_equal + greater_than(">"), + greater_than_or_equal(">="), + less_than("<"), + less_than_or_equal("<="); private final String representation; @@ -58,6 +65,21 @@ public class ExpressionEvaluator { throw new IllegalArgumentException("Unsupported operator " + comparator); } + if(actual == null){ + if(operator == Operator.equal){ + return NULL_VALUE.equals(expected); + } else if(operator == Operator.not_equal || operator == Operator.less_or_greater_than){ + return !NULL_VALUE.equals(expected); + } + } else { + if(operator == Operator.not_equal || operator == Operator.less_or_greater_than){ + if(NULL_VALUE.equals(expected)){ + return true; + } + } + } + + if (actual instanceof Long) { Long a = (Long) actual; @@ -173,7 +195,7 @@ public class ExpressionEvaluator { BigInteger a = (BigInteger) actual; BigInteger e = new BigInteger(expected.trim()); - switch (operator){ + switch (operator) { case equal: return a.compareTo(e) == 0; case not_equal: @@ -196,7 +218,7 @@ public class ExpressionEvaluator { BigDecimal a = (BigDecimal) actual; BigDecimal e = new BigDecimal(expected); - switch (operator){ + switch (operator) { case equal: return a.compareTo(e) == 0; case not_equal: diff --git a/json-path/src/test/java/com/jayway/jsonpath/ExpressionEvalTest.java b/json-path/src/test/java/com/jayway/jsonpath/ExpressionEvalTest.java index 8543d605..fc101ad8 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/ExpressionEvalTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/ExpressionEvalTest.java @@ -6,7 +6,10 @@ import org.junit.Test; import java.math.BigDecimal; import java.math.BigInteger; +import java.util.List; +import java.util.Map; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -18,6 +21,51 @@ import static org.junit.Assert.assertTrue; */ public class ExpressionEvalTest { + public static final String DOCUMENT= "{\n" + + " \"characters\": [\n" + + " {\n" + + " \"aliases\": [], \n" + + " \"name\": \"Kleeg Lars\", \n" + + " \"occupation\": \"Moisture farmer\", \n" + + " \"offspring\": []\n" + + " }, \n" + + " {\n" + + " \"aliases\": [], \n" + + " \"name\": \"Shmi Skywalker\", \n" + + " \"occupation\": \"Virgin mother\", \n" + + " \"offspring\": [\n" + + " \"AnakinSkywalker\"\n" + + " ]\n" + + " }, \n" + + " {\n" + + " \"aliases\": [\n" + + " \"Darth Vader\"\n" + + " ], \n" + + " \"name\": \"Annakin Skywalker\", \n" + + " \"occupation\": \"Hand of the Emperor, Lord of the Sith\", \n" + + " \"offspring\": [\n" + + " \"Luke Skywalker\", \n" + + " \"LeiaOrgana\"\n" + + " ]\n" + + " }, \n" + + " {\n" + + " \"aliases\": [\n" + + " \"Nerf herder\"\n" + + " ], \n" + + " \"name\": \"Luke Skywalker\", \n" + + " \"occupation\": \"Farm boy\", \n" + + " \"offspring\": null\n" + + " }, \n" + + " {\n" + + " \"aliases\": [\n" + + " \"Your Highness\"\n" + + " ], \n" + + " \"name\": \"Leia Organa\", \n" + + " \"occupation\": \"Senator\", \n" + + " }\n" + + " ]\n" + + "}\n"; + @Test public void long_eval() throws Exception { @@ -117,8 +165,42 @@ public class ExpressionEvalTest { assertFalse(ExpressionEvaluator.eval(false, "==", "true")); assertFalse(ExpressionEvaluator.eval(true, "!=", "true")); assertFalse(ExpressionEvaluator.eval(true, "<>", "true")); - assertFalse(ExpressionEvaluator.eval(false, "!=", "false")); assertFalse(ExpressionEvaluator.eval(false, "<>", "false")); + assertFalse(ExpressionEvaluator.eval(false, "!=", "false")); + + } + + @Test + public void null_eval() throws Exception { + assertTrue(ExpressionEvaluator.eval(new Integer(10), "!=", "null")); + + assertTrue(ExpressionEvaluator.eval(null, "==", "null")); + + assertTrue(ExpressionEvaluator.eval(null, "<>", "FOO")); + assertTrue(ExpressionEvaluator.eval("FOO", "<>", "null")); + + + assertTrue(ExpressionEvaluator.eval(null, "!=", "FOO")); + assertTrue(ExpressionEvaluator.eval("FOO", "<>", "null")); + + assertTrue(ExpressionEvaluator.eval(null, "!=", "10")); + } + + + @Test + public void nulls_filter() { + + List> result = JsonPath.read(DOCUMENT, "$.characters[?(@.offspring == null)]"); + assertEquals(1, result.size()); + + result = JsonPath.read(DOCUMENT, "$.characters[?(@.offspring != null)]"); + assertEquals(3, result.size()); + + result = JsonPath.read(DOCUMENT, "$.characters[?(@.offspring)]"); + assertEquals(4, result.size()); + + + }