Implement JsonPath in JsonReader.
This commit is contained in:
parent
80bbf4a85a
commit
fbc7e69c81
@ -272,6 +272,17 @@ public class JsonReader implements Closeable {
|
|||||||
stack[stackSize++] = JsonScope.EMPTY_DOCUMENT;
|
stack[stackSize++] = JsonScope.EMPTY_DOCUMENT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The path members. It corresponds directly to stack: At indices where the
|
||||||
|
* stack contains an object (EMPTY_OBJECT, DANGLING_NAME or NONEMPTY_OBJECT),
|
||||||
|
* pathNames contains the name at this scope. Where it contains an array
|
||||||
|
* (EMPTY_ARRAY, NONEMPTY_ARRAY) pathIndices contains the current index in
|
||||||
|
* that array. Otherwise the value is undefined, and we take advantage of that
|
||||||
|
* by incrementing pathIndices when doing so isn't useful.
|
||||||
|
*/
|
||||||
|
private String[] pathNames = new String[32];
|
||||||
|
private int[] pathIndices = new int[32];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance that reads a JSON-encoded stream from {@code in}.
|
* Creates a new instance that reads a JSON-encoded stream from {@code in}.
|
||||||
*/
|
*/
|
||||||
@ -333,10 +344,11 @@ public class JsonReader implements Closeable {
|
|||||||
}
|
}
|
||||||
if (p == PEEKED_BEGIN_ARRAY) {
|
if (p == PEEKED_BEGIN_ARRAY) {
|
||||||
push(JsonScope.EMPTY_ARRAY);
|
push(JsonScope.EMPTY_ARRAY);
|
||||||
|
pathIndices[stackSize - 1] = 0;
|
||||||
peeked = PEEKED_NONE;
|
peeked = PEEKED_NONE;
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException("Expected BEGIN_ARRAY but was " + peek()
|
throw new IllegalStateException("Expected BEGIN_ARRAY but was " + peek()
|
||||||
+ " at line " + getLineNumber() + " column " + getColumnNumber());
|
+ " at line " + getLineNumber() + " column " + getColumnNumber() + " path " + getPath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -354,7 +366,7 @@ public class JsonReader implements Closeable {
|
|||||||
peeked = PEEKED_NONE;
|
peeked = PEEKED_NONE;
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException("Expected END_ARRAY but was " + peek()
|
throw new IllegalStateException("Expected END_ARRAY but was " + peek()
|
||||||
+ " at line " + getLineNumber() + " column " + getColumnNumber());
|
+ " at line " + getLineNumber() + " column " + getColumnNumber() + " path " + getPath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -372,7 +384,7 @@ public class JsonReader implements Closeable {
|
|||||||
peeked = PEEKED_NONE;
|
peeked = PEEKED_NONE;
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException("Expected BEGIN_OBJECT but was " + peek()
|
throw new IllegalStateException("Expected BEGIN_OBJECT but was " + peek()
|
||||||
+ " at line " + getLineNumber() + " column " + getColumnNumber());
|
+ " at line " + getLineNumber() + " column " + getColumnNumber() + " path " + getPath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -387,10 +399,11 @@ public class JsonReader implements Closeable {
|
|||||||
}
|
}
|
||||||
if (p == PEEKED_END_OBJECT) {
|
if (p == PEEKED_END_OBJECT) {
|
||||||
stackSize--;
|
stackSize--;
|
||||||
|
pathNames[stackSize] = null; // Free the last path name so that it can be garbage collected!
|
||||||
peeked = PEEKED_NONE;
|
peeked = PEEKED_NONE;
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException("Expected END_OBJECT but was " + peek()
|
throw new IllegalStateException("Expected END_OBJECT but was " + peek()
|
||||||
+ " at line " + getLineNumber() + " column " + getColumnNumber());
|
+ " at line " + getLineNumber() + " column " + getColumnNumber() + " path " + getPath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -783,9 +796,10 @@ public class JsonReader implements Closeable {
|
|||||||
result = nextQuotedValue('"');
|
result = nextQuotedValue('"');
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException("Expected a name but was " + peek()
|
throw new IllegalStateException("Expected a name but was " + peek()
|
||||||
+ " at line " + getLineNumber() + " column " + getColumnNumber());
|
+ " at line " + getLineNumber() + " column " + getColumnNumber() + " path " + getPath());
|
||||||
}
|
}
|
||||||
peeked = PEEKED_NONE;
|
peeked = PEEKED_NONE;
|
||||||
|
pathNames[stackSize - 1] = result;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -819,9 +833,10 @@ public class JsonReader implements Closeable {
|
|||||||
pos += peekedNumberLength;
|
pos += peekedNumberLength;
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException("Expected a string but was " + peek()
|
throw new IllegalStateException("Expected a string but was " + peek()
|
||||||
+ " at line " + getLineNumber() + " column " + getColumnNumber());
|
+ " at line " + getLineNumber() + " column " + getColumnNumber() + " path " + getPath());
|
||||||
}
|
}
|
||||||
peeked = PEEKED_NONE;
|
peeked = PEEKED_NONE;
|
||||||
|
pathIndices[stackSize - 1]++;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -839,13 +854,15 @@ public class JsonReader implements Closeable {
|
|||||||
}
|
}
|
||||||
if (p == PEEKED_TRUE) {
|
if (p == PEEKED_TRUE) {
|
||||||
peeked = PEEKED_NONE;
|
peeked = PEEKED_NONE;
|
||||||
|
pathIndices[stackSize - 1]++;
|
||||||
return true;
|
return true;
|
||||||
} else if (p == PEEKED_FALSE) {
|
} else if (p == PEEKED_FALSE) {
|
||||||
peeked = PEEKED_NONE;
|
peeked = PEEKED_NONE;
|
||||||
|
pathIndices[stackSize - 1]++;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
throw new IllegalStateException("Expected a boolean but was " + peek()
|
throw new IllegalStateException("Expected a boolean but was " + peek()
|
||||||
+ " at line " + getLineNumber() + " column " + getColumnNumber());
|
+ " at line " + getLineNumber() + " column " + getColumnNumber() + " path " + getPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -862,9 +879,10 @@ public class JsonReader implements Closeable {
|
|||||||
}
|
}
|
||||||
if (p == PEEKED_NULL) {
|
if (p == PEEKED_NULL) {
|
||||||
peeked = PEEKED_NONE;
|
peeked = PEEKED_NONE;
|
||||||
|
pathIndices[stackSize - 1]++;
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException("Expected null but was " + peek()
|
throw new IllegalStateException("Expected null but was " + peek()
|
||||||
+ " at line " + getLineNumber() + " column " + getColumnNumber());
|
+ " at line " + getLineNumber() + " column " + getColumnNumber() + " path " + getPath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -885,6 +903,7 @@ public class JsonReader implements Closeable {
|
|||||||
|
|
||||||
if (p == PEEKED_LONG) {
|
if (p == PEEKED_LONG) {
|
||||||
peeked = PEEKED_NONE;
|
peeked = PEEKED_NONE;
|
||||||
|
pathIndices[stackSize - 1]++;
|
||||||
return (double) peekedLong;
|
return (double) peekedLong;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -897,17 +916,18 @@ public class JsonReader implements Closeable {
|
|||||||
peekedString = nextUnquotedValue();
|
peekedString = nextUnquotedValue();
|
||||||
} else if (p != PEEKED_BUFFERED) {
|
} else if (p != PEEKED_BUFFERED) {
|
||||||
throw new IllegalStateException("Expected a double but was " + peek()
|
throw new IllegalStateException("Expected a double but was " + peek()
|
||||||
+ " at line " + getLineNumber() + " column " + getColumnNumber());
|
+ " at line " + getLineNumber() + " column " + getColumnNumber() + " path " + getPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
peeked = PEEKED_BUFFERED;
|
peeked = PEEKED_BUFFERED;
|
||||||
double result = Double.parseDouble(peekedString); // don't catch this NumberFormatException.
|
double result = Double.parseDouble(peekedString); // don't catch this NumberFormatException.
|
||||||
if (!lenient && (Double.isNaN(result) || Double.isInfinite(result))) {
|
if (!lenient && (Double.isNaN(result) || Double.isInfinite(result))) {
|
||||||
throw new MalformedJsonException("JSON forbids NaN and infinities: " + result
|
throw new MalformedJsonException("JSON forbids NaN and infinities: " + result
|
||||||
+ " at line " + getLineNumber() + " column " + getColumnNumber());
|
+ " at line " + getLineNumber() + " column " + getColumnNumber() + " path " + getPath());
|
||||||
}
|
}
|
||||||
peekedString = null;
|
peekedString = null;
|
||||||
peeked = PEEKED_NONE;
|
peeked = PEEKED_NONE;
|
||||||
|
pathIndices[stackSize - 1]++;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -929,6 +949,7 @@ public class JsonReader implements Closeable {
|
|||||||
|
|
||||||
if (p == PEEKED_LONG) {
|
if (p == PEEKED_LONG) {
|
||||||
peeked = PEEKED_NONE;
|
peeked = PEEKED_NONE;
|
||||||
|
pathIndices[stackSize - 1]++;
|
||||||
return peekedLong;
|
return peekedLong;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -940,13 +961,14 @@ public class JsonReader implements Closeable {
|
|||||||
try {
|
try {
|
||||||
long result = Long.parseLong(peekedString);
|
long result = Long.parseLong(peekedString);
|
||||||
peeked = PEEKED_NONE;
|
peeked = PEEKED_NONE;
|
||||||
|
pathIndices[stackSize - 1]++;
|
||||||
return result;
|
return result;
|
||||||
} catch (NumberFormatException ignored) {
|
} catch (NumberFormatException ignored) {
|
||||||
// Fall back to parse as a double below.
|
// Fall back to parse as a double below.
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException("Expected a long but was " + peek()
|
throw new IllegalStateException("Expected a long but was " + peek()
|
||||||
+ " at line " + getLineNumber() + " column " + getColumnNumber());
|
+ " at line " + getLineNumber() + " column " + getColumnNumber() + " path " + getPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
peeked = PEEKED_BUFFERED;
|
peeked = PEEKED_BUFFERED;
|
||||||
@ -954,10 +976,11 @@ public class JsonReader implements Closeable {
|
|||||||
long result = (long) asDouble;
|
long result = (long) asDouble;
|
||||||
if (result != asDouble) { // Make sure no precision was lost casting to 'long'.
|
if (result != asDouble) { // Make sure no precision was lost casting to 'long'.
|
||||||
throw new NumberFormatException("Expected a long but was " + peekedString
|
throw new NumberFormatException("Expected a long but was " + peekedString
|
||||||
+ " at line " + getLineNumber() + " column " + getColumnNumber());
|
+ " at line " + getLineNumber() + " column " + getColumnNumber() + " path " + getPath());
|
||||||
}
|
}
|
||||||
peekedString = null;
|
peekedString = null;
|
||||||
peeked = PEEKED_NONE;
|
peeked = PEEKED_NONE;
|
||||||
|
pathIndices[stackSize - 1]++;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1151,9 +1174,10 @@ public class JsonReader implements Closeable {
|
|||||||
result = (int) peekedLong;
|
result = (int) peekedLong;
|
||||||
if (peekedLong != result) { // Make sure no precision was lost casting to 'int'.
|
if (peekedLong != result) { // Make sure no precision was lost casting to 'int'.
|
||||||
throw new NumberFormatException("Expected an int but was " + peekedLong
|
throw new NumberFormatException("Expected an int but was " + peekedLong
|
||||||
+ " at line " + getLineNumber() + " column " + getColumnNumber());
|
+ " at line " + getLineNumber() + " column " + getColumnNumber() + " path " + getPath());
|
||||||
}
|
}
|
||||||
peeked = PEEKED_NONE;
|
peeked = PEEKED_NONE;
|
||||||
|
pathIndices[stackSize - 1]++;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1165,13 +1189,14 @@ public class JsonReader implements Closeable {
|
|||||||
try {
|
try {
|
||||||
result = Integer.parseInt(peekedString);
|
result = Integer.parseInt(peekedString);
|
||||||
peeked = PEEKED_NONE;
|
peeked = PEEKED_NONE;
|
||||||
|
pathIndices[stackSize - 1]++;
|
||||||
return result;
|
return result;
|
||||||
} catch (NumberFormatException ignored) {
|
} catch (NumberFormatException ignored) {
|
||||||
// Fall back to parse as a double below.
|
// Fall back to parse as a double below.
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException("Expected an int but was " + peek()
|
throw new IllegalStateException("Expected an int but was " + peek()
|
||||||
+ " at line " + getLineNumber() + " column " + getColumnNumber());
|
+ " at line " + getLineNumber() + " column " + getColumnNumber() + " path " + getPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
peeked = PEEKED_BUFFERED;
|
peeked = PEEKED_BUFFERED;
|
||||||
@ -1179,10 +1204,11 @@ public class JsonReader implements Closeable {
|
|||||||
result = (int) asDouble;
|
result = (int) asDouble;
|
||||||
if (result != asDouble) { // Make sure no precision was lost casting to 'int'.
|
if (result != asDouble) { // Make sure no precision was lost casting to 'int'.
|
||||||
throw new NumberFormatException("Expected an int but was " + peekedString
|
throw new NumberFormatException("Expected an int but was " + peekedString
|
||||||
+ " at line " + getLineNumber() + " column " + getColumnNumber());
|
+ " at line " + getLineNumber() + " column " + getColumnNumber() + " path " + getPath());
|
||||||
}
|
}
|
||||||
peekedString = null;
|
peekedString = null;
|
||||||
peeked = PEEKED_NONE;
|
peeked = PEEKED_NONE;
|
||||||
|
pathIndices[stackSize - 1]++;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1232,13 +1258,22 @@ public class JsonReader implements Closeable {
|
|||||||
}
|
}
|
||||||
peeked = PEEKED_NONE;
|
peeked = PEEKED_NONE;
|
||||||
} while (count != 0);
|
} while (count != 0);
|
||||||
|
|
||||||
|
pathIndices[stackSize - 1]++;
|
||||||
|
pathNames[stackSize - 1] = "null";
|
||||||
}
|
}
|
||||||
|
|
||||||
private void push(int newTop) {
|
private void push(int newTop) {
|
||||||
if (stackSize == stack.length) {
|
if (stackSize == stack.length) {
|
||||||
int[] newStack = new int[stackSize * 2];
|
int[] newStack = new int[stackSize * 2];
|
||||||
|
int[] newPathIndices = new int[stackSize * 2];
|
||||||
|
String[] newPathNames = new String[stackSize * 2];
|
||||||
System.arraycopy(stack, 0, newStack, 0, stackSize);
|
System.arraycopy(stack, 0, newStack, 0, stackSize);
|
||||||
|
System.arraycopy(pathIndices, 0, newPathIndices, 0, stackSize);
|
||||||
|
System.arraycopy(pathNames, 0, newPathNames, 0, stackSize);
|
||||||
stack = newStack;
|
stack = newStack;
|
||||||
|
pathIndices = newPathIndices;
|
||||||
|
pathNames = newPathNames;
|
||||||
}
|
}
|
||||||
stack[stackSize++] = newTop;
|
stack[stackSize++] = newTop;
|
||||||
}
|
}
|
||||||
@ -1431,6 +1466,37 @@ public class JsonReader implements Closeable {
|
|||||||
+ " at line " + getLineNumber() + " column " + getColumnNumber();
|
+ " at line " + getLineNumber() + " column " + getColumnNumber();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a <a href="http://goessner.net/articles/JsonPath/">JsonPath</a> to
|
||||||
|
* the current location in the JSON value.
|
||||||
|
*/
|
||||||
|
public String getPath() {
|
||||||
|
StringBuilder result = new StringBuilder().append('$');
|
||||||
|
for (int i = 0, size = stackSize; i < size; i++) {
|
||||||
|
switch (stack[i]) {
|
||||||
|
case JsonScope.EMPTY_ARRAY:
|
||||||
|
case JsonScope.NONEMPTY_ARRAY:
|
||||||
|
result.append('[').append(pathIndices[i]).append(']');
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JsonScope.EMPTY_OBJECT:
|
||||||
|
case JsonScope.DANGLING_NAME:
|
||||||
|
case JsonScope.NONEMPTY_OBJECT:
|
||||||
|
result.append('.');
|
||||||
|
if (pathNames[i] != null) {
|
||||||
|
result.append(pathNames[i]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case JsonScope.NONEMPTY_DOCUMENT:
|
||||||
|
case JsonScope.EMPTY_DOCUMENT:
|
||||||
|
case JsonScope.CLOSED:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result.toString();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unescapes the character identified by the character or characters that
|
* Unescapes the character identified by the character or characters that
|
||||||
* immediately follow a backslash. The backslash '\' should have already
|
* immediately follow a backslash. The backslash '\' should have already
|
||||||
@ -1503,7 +1569,7 @@ public class JsonReader implements Closeable {
|
|||||||
*/
|
*/
|
||||||
private IOException syntaxError(String message) throws IOException {
|
private IOException syntaxError(String message) throws IOException {
|
||||||
throw new MalformedJsonException(message
|
throw new MalformedJsonException(message
|
||||||
+ " at line " + getLineNumber() + " column " + getColumnNumber());
|
+ " at line " + getLineNumber() + " column " + getColumnNumber() + " path " + getPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1547,7 +1613,8 @@ public class JsonReader implements Closeable {
|
|||||||
reader.peeked = PEEKED_UNQUOTED;
|
reader.peeked = PEEKED_UNQUOTED;
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException("Expected a name but was " + reader.peek() + " "
|
throw new IllegalStateException("Expected a name but was " + reader.peek() + " "
|
||||||
+ " at line " + reader.getLineNumber() + " column " + reader.getColumnNumber());
|
+ " at line " + reader.getLineNumber() + " column " + reader.getColumnNumber()
|
||||||
|
+ " path " + reader.getPath());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -0,0 +1,176 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2014 Google Inc.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.google.gson.stream;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.StringReader;
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
public class JsonReaderPathTest extends TestCase {
|
||||||
|
public void testPath() throws IOException {
|
||||||
|
JsonReader reader = new JsonReader(
|
||||||
|
new StringReader("{\"a\":[2,true,false,null,\"b\",{\"c\":\"d\"},[3]]}"));
|
||||||
|
assertEquals("$", reader.getPath());
|
||||||
|
reader.beginObject();
|
||||||
|
assertEquals("$.", reader.getPath());
|
||||||
|
reader.nextName();
|
||||||
|
assertEquals("$.a", reader.getPath());
|
||||||
|
reader.beginArray();
|
||||||
|
assertEquals("$.a[0]", reader.getPath());
|
||||||
|
reader.nextInt();
|
||||||
|
assertEquals("$.a[1]", reader.getPath());
|
||||||
|
reader.nextBoolean();
|
||||||
|
assertEquals("$.a[2]", reader.getPath());
|
||||||
|
reader.nextBoolean();
|
||||||
|
assertEquals("$.a[3]", reader.getPath());
|
||||||
|
reader.nextNull();
|
||||||
|
assertEquals("$.a[4]", reader.getPath());
|
||||||
|
reader.nextString();
|
||||||
|
assertEquals("$.a[5]", reader.getPath());
|
||||||
|
reader.beginObject();
|
||||||
|
assertEquals("$.a[5].", reader.getPath());
|
||||||
|
reader.nextName();
|
||||||
|
assertEquals("$.a[5].c", reader.getPath());
|
||||||
|
reader.nextString();
|
||||||
|
assertEquals("$.a[5].c", reader.getPath());
|
||||||
|
reader.endObject();
|
||||||
|
assertEquals("$.a[5]", reader.getPath());
|
||||||
|
reader.beginArray();
|
||||||
|
assertEquals("$.a[5][0]", reader.getPath());
|
||||||
|
reader.nextInt();
|
||||||
|
assertEquals("$.a[5][1]", reader.getPath());
|
||||||
|
reader.endArray();
|
||||||
|
assertEquals("$.a[5]", reader.getPath());
|
||||||
|
reader.endArray();
|
||||||
|
assertEquals("$.a", reader.getPath());
|
||||||
|
reader.endObject();
|
||||||
|
assertEquals("$", reader.getPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testObjectPath() throws IOException {
|
||||||
|
JsonReader reader = new JsonReader(new StringReader("{\"a\":1,\"b\":2}"));
|
||||||
|
assertEquals("$", reader.getPath());
|
||||||
|
|
||||||
|
reader.peek();
|
||||||
|
assertEquals("$", reader.getPath());
|
||||||
|
reader.beginObject();
|
||||||
|
assertEquals("$.", reader.getPath());
|
||||||
|
|
||||||
|
reader.peek();
|
||||||
|
assertEquals("$.", reader.getPath());
|
||||||
|
reader.nextName();
|
||||||
|
assertEquals("$.a", reader.getPath());
|
||||||
|
|
||||||
|
reader.peek();
|
||||||
|
assertEquals("$.a", reader.getPath());
|
||||||
|
reader.nextInt();
|
||||||
|
assertEquals("$.a", reader.getPath());
|
||||||
|
|
||||||
|
reader.peek();
|
||||||
|
assertEquals("$.a", reader.getPath());
|
||||||
|
reader.nextName();
|
||||||
|
assertEquals("$.b", reader.getPath());
|
||||||
|
|
||||||
|
reader.peek();
|
||||||
|
assertEquals("$.b", reader.getPath());
|
||||||
|
reader.nextInt();
|
||||||
|
assertEquals("$.b", reader.getPath());
|
||||||
|
|
||||||
|
reader.peek();
|
||||||
|
assertEquals("$.b", reader.getPath());
|
||||||
|
reader.endObject();
|
||||||
|
assertEquals("$", reader.getPath());
|
||||||
|
|
||||||
|
reader.peek();
|
||||||
|
assertEquals("$", reader.getPath());
|
||||||
|
reader.close();
|
||||||
|
assertEquals("$", reader.getPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testArrayPath() throws IOException {
|
||||||
|
JsonReader reader = new JsonReader(new StringReader("[1,2]"));
|
||||||
|
assertEquals("$", reader.getPath());
|
||||||
|
|
||||||
|
reader.peek();
|
||||||
|
assertEquals("$", reader.getPath());
|
||||||
|
reader.beginArray();
|
||||||
|
assertEquals("$[0]", reader.getPath());
|
||||||
|
|
||||||
|
reader.peek();
|
||||||
|
assertEquals("$[0]", reader.getPath());
|
||||||
|
reader.nextInt();
|
||||||
|
assertEquals("$[1]", reader.getPath());
|
||||||
|
|
||||||
|
reader.peek();
|
||||||
|
assertEquals("$[1]", reader.getPath());
|
||||||
|
reader.nextInt();
|
||||||
|
assertEquals("$[2]", reader.getPath());
|
||||||
|
|
||||||
|
reader.peek();
|
||||||
|
assertEquals("$[2]", reader.getPath());
|
||||||
|
reader.endArray();
|
||||||
|
assertEquals("$", reader.getPath());
|
||||||
|
|
||||||
|
reader.peek();
|
||||||
|
assertEquals("$", reader.getPath());
|
||||||
|
reader.close();
|
||||||
|
assertEquals("$", reader.getPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testMultipleTopLevelValuesInOneDocument() throws IOException {
|
||||||
|
JsonReader reader = new JsonReader(new StringReader("[][]"));
|
||||||
|
reader.setLenient(true);
|
||||||
|
reader.beginArray();
|
||||||
|
reader.endArray();
|
||||||
|
assertEquals("$", reader.getPath());
|
||||||
|
reader.beginArray();
|
||||||
|
reader.endArray();
|
||||||
|
assertEquals("$", reader.getPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSkipArrayElements() throws IOException {
|
||||||
|
JsonReader reader = new JsonReader(new StringReader("[1,2,3]"));
|
||||||
|
reader.beginArray();
|
||||||
|
reader.skipValue();
|
||||||
|
reader.skipValue();
|
||||||
|
assertEquals("$[2]", reader.getPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSkipObjectNames() throws IOException {
|
||||||
|
JsonReader reader = new JsonReader(new StringReader("{\"a\":1}"));
|
||||||
|
reader.beginObject();
|
||||||
|
reader.skipValue();
|
||||||
|
assertEquals("$.null", reader.getPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSkipObjectValues() throws IOException {
|
||||||
|
JsonReader reader = new JsonReader(new StringReader("{\"a\":1,\"b\":2}"));
|
||||||
|
reader.beginObject();
|
||||||
|
reader.nextName();
|
||||||
|
reader.skipValue();
|
||||||
|
assertEquals("$.null", reader.getPath());
|
||||||
|
reader.nextName();
|
||||||
|
assertEquals("$.b", reader.getPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSkipNestedStructures() throws IOException {
|
||||||
|
JsonReader reader = new JsonReader(new StringReader("[[1,2,3],4]"));
|
||||||
|
reader.beginArray();
|
||||||
|
reader.skipValue();
|
||||||
|
assertEquals("$[1]", reader.getPath());
|
||||||
|
}
|
||||||
|
}
|
@ -1326,45 +1326,46 @@ public final class JsonReaderTest extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void testFailWithPosition() throws IOException {
|
public void testFailWithPosition() throws IOException {
|
||||||
testFailWithPosition("Expected value at line 6 column 5",
|
testFailWithPosition("Expected value at line 6 column 5 path $[1]",
|
||||||
"[\n\n\n\n\n\"a\",}]");
|
"[\n\n\n\n\n\"a\",}]");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testFailWithPositionGreaterThanBufferSize() throws IOException {
|
public void testFailWithPositionGreaterThanBufferSize() throws IOException {
|
||||||
String spaces = repeat(' ', 8192);
|
String spaces = repeat(' ', 8192);
|
||||||
testFailWithPosition("Expected value at line 6 column 5",
|
testFailWithPosition("Expected value at line 6 column 5 path $[1]",
|
||||||
"[\n\n" + spaces + "\n\n\n\"a\",}]");
|
"[\n\n" + spaces + "\n\n\n\"a\",}]");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testFailWithPositionOverSlashSlashEndOfLineComment() throws IOException {
|
public void testFailWithPositionOverSlashSlashEndOfLineComment() throws IOException {
|
||||||
testFailWithPosition("Expected value at line 5 column 6",
|
testFailWithPosition("Expected value at line 5 column 6 path $[1]",
|
||||||
"\n// foo\n\n//bar\r\n[\"a\",}");
|
"\n// foo\n\n//bar\r\n[\"a\",}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testFailWithPositionOverHashEndOfLineComment() throws IOException {
|
public void testFailWithPositionOverHashEndOfLineComment() throws IOException {
|
||||||
testFailWithPosition("Expected value at line 5 column 6",
|
testFailWithPosition("Expected value at line 5 column 6 path $[1]",
|
||||||
"\n# foo\n\n#bar\r\n[\"a\",}");
|
"\n# foo\n\n#bar\r\n[\"a\",}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testFailWithPositionOverCStyleComment() throws IOException {
|
public void testFailWithPositionOverCStyleComment() throws IOException {
|
||||||
testFailWithPosition("Expected value at line 6 column 12",
|
testFailWithPosition("Expected value at line 6 column 12 path $[1]",
|
||||||
"\n\n/* foo\n*\n*\r\nbar */[\"a\",}");
|
"\n\n/* foo\n*\n*\r\nbar */[\"a\",}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testFailWithPositionOverQuotedString() throws IOException {
|
public void testFailWithPositionOverQuotedString() throws IOException {
|
||||||
testFailWithPosition("Expected value at line 5 column 3", "[\"foo\nbar\r\nbaz\n\",\n }");
|
testFailWithPosition("Expected value at line 5 column 3 path $[1]",
|
||||||
|
"[\"foo\nbar\r\nbaz\n\",\n }");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testFailWithPositionOverUnquotedString() throws IOException {
|
public void testFailWithPositionOverUnquotedString() throws IOException {
|
||||||
testFailWithPosition("Expected value at line 5 column 2", "[\n\nabcd\n\n,}");
|
testFailWithPosition("Expected value at line 5 column 2 path $[1]", "[\n\nabcd\n\n,}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testFailWithEscapedNewlineCharacter() throws IOException {
|
public void testFailWithEscapedNewlineCharacter() throws IOException {
|
||||||
testFailWithPosition("Expected value at line 5 column 3", "[\n\n\"\\\n\n\",}");
|
testFailWithPosition("Expected value at line 5 column 3 path $[1]", "[\n\n\"\\\n\n\",}");
|
||||||
}
|
}
|
||||||
|
|
||||||
public void testFailWithPositionIsOffsetByBom() throws IOException {
|
public void testFailWithPositionIsOffsetByBom() throws IOException {
|
||||||
testFailWithPosition("Expected value at line 1 column 6",
|
testFailWithPosition("Expected value at line 1 column 6 path $[1]",
|
||||||
"\ufeff[\"a\",}]");
|
"\ufeff[\"a\",}]");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1394,6 +1395,23 @@ public final class JsonReaderTest extends TestCase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testFailWithPositionDeepPath() throws IOException {
|
||||||
|
JsonReader reader = new JsonReader(reader("[1,{\"a\":[2,3,}"));
|
||||||
|
reader.beginArray();
|
||||||
|
reader.nextInt();
|
||||||
|
reader.beginObject();
|
||||||
|
reader.nextName();
|
||||||
|
reader.beginArray();
|
||||||
|
reader.nextInt();
|
||||||
|
reader.nextInt();
|
||||||
|
try {
|
||||||
|
reader.peek();
|
||||||
|
fail();
|
||||||
|
} catch (IOException expected) {
|
||||||
|
assertEquals("Expected value at line 1 column 14 path $[1].a[2]", expected.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void testStrictVeryLongNumber() throws IOException {
|
public void testStrictVeryLongNumber() throws IOException {
|
||||||
JsonReader reader = new JsonReader(reader("[0." + repeat('9', 8192) + "]"));
|
JsonReader reader = new JsonReader(reader("[0." + repeat('9', 8192) + "]"));
|
||||||
reader.beginArray();
|
reader.beginArray();
|
||||||
@ -1430,6 +1448,8 @@ public final class JsonReaderTest extends TestCase {
|
|||||||
for (int i = 0; i < 40; i++) {
|
for (int i = 0; i < 40; i++) {
|
||||||
reader.beginArray();
|
reader.beginArray();
|
||||||
}
|
}
|
||||||
|
assertEquals("$[0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0][0]"
|
||||||
|
+ "[0][0][0][0][0][0][0][0][0][0][0][0][0][0]", reader.getPath());
|
||||||
for (int i = 0; i < 40; i++) {
|
for (int i = 0; i < 40; i++) {
|
||||||
reader.endArray();
|
reader.endArray();
|
||||||
}
|
}
|
||||||
@ -1449,6 +1469,8 @@ public final class JsonReaderTest extends TestCase {
|
|||||||
reader.beginObject();
|
reader.beginObject();
|
||||||
assertEquals("a", reader.nextName());
|
assertEquals("a", reader.nextName());
|
||||||
}
|
}
|
||||||
|
assertEquals("$.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a"
|
||||||
|
+ ".a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a.a", reader.getPath());
|
||||||
assertEquals(true, reader.nextBoolean());
|
assertEquals(true, reader.nextBoolean());
|
||||||
for (int i = 0; i < 40; i++) {
|
for (int i = 0; i < 40; i++) {
|
||||||
reader.endObject();
|
reader.endObject();
|
||||||
|
Loading…
Reference in New Issue
Block a user