From 49df9f8ed8d1b74d1bc4c16680622b34ae3fdd42 Mon Sep 17 00:00:00 2001 From: Robert Yokota Date: Sun, 24 May 2026 11:46:16 -0700 Subject: [PATCH] Preserve JSON null when indexing into an array --- src/main/java/com/dashjoin/jsonata/Jsonata.java | 13 ++++++++++--- .../java/com/dashjoin/jsonata/NullSafetyTest.java | 12 ++++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/dashjoin/jsonata/Jsonata.java b/src/main/java/com/dashjoin/jsonata/Jsonata.java index 90c7764..2583966 100644 --- a/src/main/java/com/dashjoin/jsonata/Jsonata.java +++ b/src/main/java/com/dashjoin/jsonata/Jsonata.java @@ -502,7 +502,10 @@ Frame createFrameFromTuple(Frame environment, Map tuple) { if( input instanceof JList && ((JList)input).tupleStream) { ((JList)results).tupleStream = true; } - if (!(input instanceof List)) { // isArray + if (input == null) { + // undefined input yields undefined output; skip filtering entirely + input = Utils.createSequence(); + } else if (!(input instanceof List)) { // isArray input = Utils.createSequence(input); } if (predicate.type.equals("number")) { @@ -511,8 +514,12 @@ Frame createFrameFromTuple(Frame environment, Map tuple) { // count in from end of array index = ((List)input).size() + index; } - var item = 0<=index && index<((List)input).size() ? ((List)input).get(index) : null; - if(item != null) { + if (0<=index && index<((List)input).size()) { + var item = ((List)input).get(index); + // Preserve JSON null at this index (vs. out-of-bounds, which is undefined) + if (item == null) { + item = NULL_VALUE; + } if(item instanceof List) { results = (List)item; } else { diff --git a/src/test/java/com/dashjoin/jsonata/NullSafetyTest.java b/src/test/java/com/dashjoin/jsonata/NullSafetyTest.java index 0a09c40..817fda9 100644 --- a/src/test/java/com/dashjoin/jsonata/NullSafetyTest.java +++ b/src/test/java/com/dashjoin/jsonata/NullSafetyTest.java @@ -71,6 +71,18 @@ public void testSingleNull() { Assertions.assertEquals(1, x); } + @Test + public void testArrayIndexPreservesNull() { + // Indexing into an array element that is JSON null must yield null, + // not be filtered out as if it were undefined. + Map data = Map.of("data", List.of( + Arrays.asList(1, null, 3), + Arrays.asList(2, null, 4), + Arrays.asList(3, null, 5))); + Object res = jsonata("[$map(data, function($row) { $row[1] })]").evaluate(data); + Assertions.assertEquals(Arrays.asList(null, null, null), res); + } + @Test public void testFilterNullLookup() { var x = Jsonata.jsonata("$filter($, function($v, $i, $a){$lookup($v, 'content')})").evaluate(