From f8bde5afa2e3fc928d57820572bb8f41546691a2 Mon Sep 17 00:00:00 2001 From: PHJ2000 <105151063+PHJ2000@users.noreply.github.com> Date: Tue, 13 Oct 2026 11:21:35 +0900 Subject: [PATCH] Handle missing array indexes in Jackson tree providers --- .../json/Jackson3JsonNodeJsonProvider.java | 6 ++- .../spi/json/JacksonJsonNodeJsonProvider.java | 6 ++- .../Jackson3JsonNodeJsonProviderTest.java | 42 +++++++++++++++++++ .../JacksonJsonNodeJsonProviderTest.java | 42 +++++++++++++++++++ 4 files changed, 94 insertions(+), 2 deletions(-) diff --git a/json-path/src/main/java/com/jayway/jsonpath/spi/json/Jackson3JsonNodeJsonProvider.java b/json-path/src/main/java/com/jayway/jsonpath/spi/json/Jackson3JsonNodeJsonProvider.java index 779a23e6e..0b84c7fe4 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/spi/json/Jackson3JsonNodeJsonProvider.java +++ b/json-path/src/main/java/com/jayway/jsonpath/spi/json/Jackson3JsonNodeJsonProvider.java @@ -133,7 +133,11 @@ public boolean isArray(Object obj) { @Override public Object getArrayIndex(Object obj, int idx) { - return toJsonArray(obj).get(idx); + JsonNode value = toJsonArray(obj).get(idx); + if (value == null) { + throw new IndexOutOfBoundsException("Index: " + idx); + } + return value; } @Override diff --git a/json-path/src/main/java/com/jayway/jsonpath/spi/json/JacksonJsonNodeJsonProvider.java b/json-path/src/main/java/com/jayway/jsonpath/spi/json/JacksonJsonNodeJsonProvider.java index ae1659277..394a42954 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/spi/json/JacksonJsonNodeJsonProvider.java +++ b/json-path/src/main/java/com/jayway/jsonpath/spi/json/JacksonJsonNodeJsonProvider.java @@ -135,7 +135,11 @@ public boolean isArray(Object obj) { @Override public Object getArrayIndex(Object obj, int idx) { - return toJsonArray(obj).get(idx); + JsonNode value = toJsonArray(obj).get(idx); + if (value == null) { + throw new IndexOutOfBoundsException("Index: " + idx); + } + return value; } @Override diff --git a/json-path/src/test/java/com/jayway/jsonpath/Jackson3JsonNodeJsonProviderTest.java b/json-path/src/test/java/com/jayway/jsonpath/Jackson3JsonNodeJsonProviderTest.java index 06b595a54..a3e81dd8a 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/Jackson3JsonNodeJsonProviderTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/Jackson3JsonNodeJsonProviderTest.java @@ -50,6 +50,48 @@ public class Jackson3JsonNodeJsonProviderTest extends BaseTest { "}" + "]"; + @Test + public void missing_array_indexes_are_not_found() { + DocumentContext context = using(JACKSON3_JSON_NODE_CONFIGURATION).parse("[1, null]"); + Assertions.assertThrows(PathNotFoundException.class, () -> context.read("$[2]")); + Assertions.assertThrows(PathNotFoundException.class, () -> context.read("$[-3]")); + + DocumentContext empty = using(JACKSON3_JSON_NODE_CONFIGURATION).parse("[]"); + Assertions.assertThrows(PathNotFoundException.class, () -> empty.read("$[0]")); + Assertions.assertThrows(PathNotFoundException.class, () -> empty.read("$[-1]")); + } + + @Test + public void existing_array_values_are_preserved() { + DocumentContext context = using(JACKSON3_JSON_NODE_CONFIGURATION).parse("[1, null]"); + assertThat(context.read("$[0]").intValue()).isEqualTo(1); + assertThat(context.read("$[-2]").intValue()).isEqualTo(1); + assertThat(context.read("$[1]").isNull()).isTrue(); + assertThat(context.read("$[-1]").isNull()).isTrue(); + } + + @Test + public void missing_array_indexes_can_be_suppressed() { + DocumentContext context = using(JACKSON3_JSON_NODE_CONFIGURATION.addOptions(Option.SUPPRESS_EXCEPTIONS)) + .parse("[null]"); + assertThat(context.read("$[1]")).isNull(); + assertThat(context.read("$[0]").isNull()).isTrue(); + } + + @Test + public void missing_array_indexes_are_excluded_from_result_lists() { + DocumentContext context = using(JACKSON3_JSON_NODE_CONFIGURATION.addOptions( + Option.SUPPRESS_EXCEPTIONS, Option.ALWAYS_RETURN_LIST)).parse("[null]"); + assertThat(context.read("$[1]").size()).isZero(); + ArrayNode existing = context.read("$[0]"); + assertThat(existing.size()).isEqualTo(1); + assertThat(existing.get(0).isNull()).isTrue(); + + ArrayNode results = using(JACKSON3_JSON_NODE_CONFIGURATION).parse("[[1], [2, null]]").read("$[*][1]"); + assertThat(results.size()).isEqualTo(1); + assertThat(results.get(0).isNull()).isTrue(); + } + @Test public void json_can_be_parsed() { ObjectNode node = using(JACKSON3_JSON_NODE_CONFIGURATION).parse(JSON_DOCUMENT).read("$"); diff --git a/json-path/src/test/java/com/jayway/jsonpath/JacksonJsonNodeJsonProviderTest.java b/json-path/src/test/java/com/jayway/jsonpath/JacksonJsonNodeJsonProviderTest.java index 1684248b2..774d44d7d 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/JacksonJsonNodeJsonProviderTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/JacksonJsonNodeJsonProviderTest.java @@ -50,6 +50,48 @@ public class JacksonJsonNodeJsonProviderTest extends BaseTest { "}" + "]"; + @Test + public void missing_array_indexes_are_not_found() { + DocumentContext context = using(JACKSON_JSON_NODE_CONFIGURATION).parse("[1, null]"); + Assertions.assertThrows(PathNotFoundException.class, () -> context.read("$[2]")); + Assertions.assertThrows(PathNotFoundException.class, () -> context.read("$[-3]")); + + DocumentContext empty = using(JACKSON_JSON_NODE_CONFIGURATION).parse("[]"); + Assertions.assertThrows(PathNotFoundException.class, () -> empty.read("$[0]")); + Assertions.assertThrows(PathNotFoundException.class, () -> empty.read("$[-1]")); + } + + @Test + public void existing_array_values_are_preserved() { + DocumentContext context = using(JACKSON_JSON_NODE_CONFIGURATION).parse("[1, null]"); + assertThat(context.read("$[0]").intValue()).isEqualTo(1); + assertThat(context.read("$[-2]").intValue()).isEqualTo(1); + assertThat(context.read("$[1]").isNull()).isTrue(); + assertThat(context.read("$[-1]").isNull()).isTrue(); + } + + @Test + public void missing_array_indexes_can_be_suppressed() { + DocumentContext context = using(JACKSON_JSON_NODE_CONFIGURATION.addOptions(Option.SUPPRESS_EXCEPTIONS)) + .parse("[null]"); + assertThat(context.read("$[1]")).isNull(); + assertThat(context.read("$[0]").isNull()).isTrue(); + } + + @Test + public void missing_array_indexes_are_excluded_from_result_lists() { + DocumentContext context = using(JACKSON_JSON_NODE_CONFIGURATION.addOptions( + Option.SUPPRESS_EXCEPTIONS, Option.ALWAYS_RETURN_LIST)).parse("[null]"); + assertThat(context.read("$[1]").size()).isZero(); + ArrayNode existing = context.read("$[0]"); + assertThat(existing.size()).isEqualTo(1); + assertThat(existing.get(0).isNull()).isTrue(); + + ArrayNode results = using(JACKSON_JSON_NODE_CONFIGURATION).parse("[[1], [2, null]]").read("$[*][1]"); + assertThat(results.size()).isEqualTo(1); + assertThat(results.get(0).isNull()).isTrue(); + } + @Test public void json_can_be_parsed() { ObjectNode node = using(JACKSON_JSON_NODE_CONFIGURATION).parse(JSON_DOCUMENT).read("$");