From 72a29abaaafc1d7a5769613267b1cbe094da4142 Mon Sep 17 00:00:00 2001 From: arimu1 <19286898+arimu1@users.noreply.github.com> Date: Thu, 6 Aug 2026 06:23:49 +0700 Subject: [PATCH] fix: support negative array index for set/delete/map (#1077) Normalize negative array indices before creating the update PathRef so set, delete, and map resolve $[-n] the same way as read. --- .../jsonpath/internal/path/PathToken.java | 3 ++- .../java/com/jayway/jsonpath/WriteTest.java | 26 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/path/PathToken.java b/json-path/src/main/java/com/jayway/jsonpath/internal/path/PathToken.java index 34cf1402b..e338d8bf6 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/path/PathToken.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/path/PathToken.java @@ -133,8 +133,9 @@ private static Object readObjectProperty(String property, Object model, Evaluati protected void handleArrayIndex(int index, String currentPath, Object model, EvaluationContextImpl ctx) { String evalPath = Utils.concat(currentPath, "[", String.valueOf(index), "]"); - PathRef pathRef = ctx.forUpdate() ? PathRef.create(model, index) : PathRef.NO_OP; + // Normalize negative indices before creating PathRef so set/delete/map match read (#1077) int effectiveIndex = index < 0 ? ctx.jsonProvider().length(model) + index : index; + PathRef pathRef = ctx.forUpdate() ? PathRef.create(model, effectiveIndex) : PathRef.NO_OP; try { Object evalHit = ctx.jsonProvider().getArrayIndex(model, effectiveIndex); if (isLeaf()) { diff --git a/json-path/src/test/java/com/jayway/jsonpath/WriteTest.java b/json-path/src/test/java/com/jayway/jsonpath/WriteTest.java index 5dfb0e3e4..a5a9862c8 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/WriteTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/WriteTest.java @@ -100,6 +100,32 @@ public void an_array_index_can_be_updated() { assertThat(res).isEqualTo("a"); } + @Test + public void a_negative_array_index_can_be_updated() { + // set/delete/map must resolve $[-1] like read (#1077) + DocumentContext ctx = parse("[\"a\",\"b\",\"c\"]"); + assertThat(ctx.read("$[-1]")).isEqualTo("c"); + + ctx.set("$[-1]", "z"); + assertThat(ctx.>json()).containsExactly("a", "b", "z"); + assertThat(ctx.read("$[-1]")).isEqualTo("z"); + } + + @Test + public void a_negative_array_index_can_be_deleted() { + DocumentContext ctx = parse("[\"a\",\"b\",\"c\"]"); + ctx.delete("$[-1]"); + assertThat(ctx.>json()).containsExactly("a", "b"); + } + + @Test + public void a_negative_array_index_can_be_mapped() { + DocumentContext ctx = parse("[\"a\",\"b\",\"c\"]"); + ctx.map("$[-1]", (currentValue, configuration) -> currentValue + "!"); + assertThat(ctx.>json()).containsExactly("a", "b", "c!"); + assertThat(ctx.read("$[-1]")).isEqualTo("c!"); + } + @Test public void an_array_slice_can_be_updated() {