From fcc81d16d654be272a7512e01dd64b70702eb532 Mon Sep 17 00:00:00 2001 From: Alexey Makeyev Date: Mon, 2 Nov 2015 17:55:24 +0300 Subject: [PATCH] fix for NumberFormatException exception during Criteria evaluation Its incorrect to break entire path evaluation - other nodes should have their chance to be found by Criteria. --- .../java/com/jayway/jsonpath/Criteria.java | 15 +++++++-- .../com/jayway/jsonpath/InlineFilterTest.java | 33 +++++++++++++++++++ .../java/com/jayway/jsonpath/TestUtils.java | 32 ++++++++++++++++++ 3 files changed, 77 insertions(+), 3 deletions(-) diff --git a/json-path/src/main/java/com/jayway/jsonpath/Criteria.java b/json-path/src/main/java/com/jayway/jsonpath/Criteria.java index 99148649..6cc45654 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/Criteria.java +++ b/json-path/src/main/java/com/jayway/jsonpath/Criteria.java @@ -955,6 +955,7 @@ public class Criteria implements Predicate { boolean leftNullish = isNullish(left); boolean rightNullish = isNullish(right); + BigDecimal bigDecimal; if (leftNullish && !rightNullish) { return -1; @@ -965,12 +966,12 @@ public class Criteria implements Predicate { } else if (left instanceof String && right instanceof String) { String expected = unescape((String) left); return expected.compareTo((String) right); - } else if (left instanceof Number && right instanceof Number) { - return new BigDecimal(left.toString()).compareTo(new BigDecimal(right.toString())); } else if (left instanceof Number && right instanceof BigDecimal) { return new BigDecimal(left.toString()).compareTo((BigDecimal)right); - } else if (left instanceof String && right instanceof Number) { + } else if (left instanceof Number && right instanceof Number) { return new BigDecimal(left.toString()).compareTo(new BigDecimal(right.toString())); + } else if (left instanceof String && right instanceof Number && (bigDecimal = safeBigDecimal((String)left)) != null) { + return bigDecimal.compareTo(new BigDecimal(right.toString())); } else if (left instanceof String && right instanceof Boolean) { Boolean e = Boolean.valueOf((String) left); Boolean a = (Boolean) right; @@ -988,6 +989,14 @@ public class Criteria implements Predicate { } } + private static BigDecimal safeBigDecimal(final String value) { + try { + return new BigDecimal(value); + } catch (NumberFormatException exc) { + return null; + } + } + private static boolean isNullish(Object o) { return (o == null || ((o instanceof String) && ("null".equals(o)))); } diff --git a/json-path/src/test/java/com/jayway/jsonpath/InlineFilterTest.java b/json-path/src/test/java/com/jayway/jsonpath/InlineFilterTest.java index a9371f9e..d734a513 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/InlineFilterTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/InlineFilterTest.java @@ -1,5 +1,8 @@ package com.jayway.jsonpath; +import static com.jayway.jsonpath.TestUtils.assertHasNoResults; +import static com.jayway.jsonpath.TestUtils.assertHasOneResult; + import org.junit.Test; import java.util.ArrayList; @@ -163,4 +166,34 @@ public class InlineFilterTest extends BaseTest { assertThat(isNull).containsExactly(new Integer[]{}); } + @Test + public void equality_check_does_not_break_evaluation() { + assertHasOneResult("[{\"value\":\"5\"}]", "$[?(@.value=='5')]"); + assertHasOneResult("[{\"value\":5}]", "$[?(@.value==5)]"); + + assertHasOneResult("[{\"value\":\"5.1.26\"}]", "$[?(@.value=='5.1.26')]"); + + assertHasNoResults("[{\"value\":\"5\"}]", "$[?(@.value=='5.1.26')]"); + assertHasNoResults("[{\"value\":5}]", "$[?(@.value=='5.1.26')]"); + assertHasNoResults("[{\"value\":5.1}]", "$[?(@.value=='5.1.26')]"); + + assertHasNoResults("[{\"value\":\"5.1.26\"}]", "$[?(@.value=='5')]"); + assertHasNoResults("[{\"value\":\"5.1.26\"}]", "$[?(@.value==5)]"); + assertHasNoResults("[{\"value\":\"5.1.26\"}]", "$[?(@.value==5.1)]"); + } + + @Test + public void lt_check_does_not_break_evaluation() { + assertHasOneResult("[{\"value\":\"5\"}]", "$[?(@.value<'7')]"); + assertHasNoResults("[{\"value\":\"7\"}]", "$[?(@.value<'5')]"); + + assertHasOneResult("[{\"value\":5}]", "$[?(@.value<7)]"); + assertHasNoResults("[{\"value\":7}]", "$[?(@.value<5)]"); + + assertHasOneResult("[{\"value\":5}]", "$[?(@.value<7.1)]"); + assertHasNoResults("[{\"value\":7}]", "$[?(@.value<5.1)]"); + + assertHasOneResult("[{\"value\":5.1}]", "$[?(@.value<7)]"); + assertHasNoResults("[{\"value\":7.1}]", "$[?(@.value<5)]"); + } } diff --git a/json-path/src/test/java/com/jayway/jsonpath/TestUtils.java b/json-path/src/test/java/com/jayway/jsonpath/TestUtils.java index 1835d65b..9da2499b 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/TestUtils.java +++ b/json-path/src/test/java/com/jayway/jsonpath/TestUtils.java @@ -1,6 +1,9 @@ package com.jayway.jsonpath; +import java.util.List; + import static com.jayway.jsonpath.JsonPath.using; +import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.fail; public final class TestUtils { @@ -29,4 +32,33 @@ public final class TestUtils { throw exc; } } + + /** + * Assertion which requires empty list as a result of indefinite path search. + * @param json json to be parsed + * @param path path to be evaluated + */ + public static void assertHasNoResults(final String json, final String path) { + assertHasResults(json, path, 0); + } + + /** + * Assertion which requires list of one element as a result of indefinite path search. + * @param json json to be parsed + * @param path path to be evaluated + */ + public static void assertHasOneResult(final String json, final String path) { + assertHasResults(json, path, 1); + } + + /** + * Shortcut for counting found nodes. + * @param json json to be parsed + * @param path path to be evaluated + * @param expectedResultCount expected number of nodes to be found + */ + public static void assertHasResults(final String json, final String path, final int expectedResultCount) { + final List result = JsonPath.parse(json).read(path); + assertThat(result).hasSize(expectedResultCount); + } }