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);
+ }
+
}