diff --git a/README.md b/README.md index 5a7a6c85..e0953842 100644 --- a/README.md +++ b/README.md @@ -155,6 +155,7 @@ Given the json | $.store.* | All things, both books and bicycles | | $.store..price | The price of everything | | $..book[2] | The third book | +| $..book[-2] | The second to last book | | $..book[0,1] | The first two books | | $..book[:2] | All books from index 0 (inclusive) until index 2 (exclusive) | | $..book[1:2] | All books from index 1 (inclusive) until index 2 (exclusive) | diff --git a/json-path/src/main/java/com/jayway/jsonpath/internal/path/ArrayIndexOperation.java b/json-path/src/main/java/com/jayway/jsonpath/internal/path/ArrayIndexOperation.java index 8fde93a9..cbfa0253 100644 --- a/json-path/src/main/java/com/jayway/jsonpath/internal/path/ArrayIndexOperation.java +++ b/json-path/src/main/java/com/jayway/jsonpath/internal/path/ArrayIndexOperation.java @@ -42,7 +42,7 @@ public class ArrayIndexOperation { //check valid chars for (int i = 0; i < operation.length(); i++) { char c = operation.charAt(i); - if (!isDigit(c) && c != ',' && c != ' ') { + if (!isDigit(c) && c != ',' && c != ' ' && c != '-') { throw new InvalidPathException("Failed to parse ArrayIndexOperation: " + operation); } } 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 dc22dda1..e4d23604 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 @@ -125,8 +125,9 @@ public abstract class PathToken { 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; + int effectiveIndex = index < 0 ? ctx.jsonProvider().length(model) + index : index; try { - Object evalHit = ctx.jsonProvider().getArrayIndex(model, index); + Object evalHit = ctx.jsonProvider().getArrayIndex(model, effectiveIndex); if (isLeaf()) { ctx.addResult(evalPath, pathRef, evalHit); } else { diff --git a/json-path/src/test/java/com/jayway/jsonpath/old/internal/ArrayIndexFilterTest.java b/json-path/src/test/java/com/jayway/jsonpath/old/internal/ArrayIndexFilterTest.java index 434775af..eaada166 100644 --- a/json-path/src/test/java/com/jayway/jsonpath/old/internal/ArrayIndexFilterTest.java +++ b/json-path/src/test/java/com/jayway/jsonpath/old/internal/ArrayIndexFilterTest.java @@ -1,6 +1,9 @@ package com.jayway.jsonpath.old.internal; import com.jayway.jsonpath.JsonPath; + +import org.junit.Assert; + import org.hamcrest.Matchers; import org.junit.Test; @@ -43,4 +46,10 @@ public class ArrayIndexFilterTest { assertThat(result, Matchers.contains(1, 3, 5)); } + @Test + public void can_access_items_from_end_with_negative_index() { + int result = JsonPath.parse(JSON).read("$[-3]"); + Assert.assertEquals(8, result); + } + }