Make default adapters stricter; improve exception messages (#2000)
* Make default adapters stricter; improve exception messages * Reduce scope of synchronized blocks * Improve JsonReader.getPath / getPreviousPath Javadoc
This commit is contained in:
parent
b3188c1132
commit
b4dab86b10
@ -71,11 +71,11 @@ public enum ToNumberPolicy implements ToNumberStrategy {
|
||||
try {
|
||||
Double d = Double.valueOf(value);
|
||||
if ((d.isInfinite() || d.isNaN()) && !in.isLenient()) {
|
||||
throw new MalformedJsonException("JSON forbids NaN and infinities: " + d + "; at path " + in.getPath());
|
||||
throw new MalformedJsonException("JSON forbids NaN and infinities: " + d + "; at path " + in.getPreviousPath());
|
||||
}
|
||||
return d;
|
||||
} catch (NumberFormatException doubleE) {
|
||||
throw new JsonParseException("Cannot parse " + value + "; at path " + in.getPath(), doubleE);
|
||||
throw new JsonParseException("Cannot parse " + value + "; at path " + in.getPreviousPath(), doubleE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -91,7 +91,7 @@ public enum ToNumberPolicy implements ToNumberStrategy {
|
||||
try {
|
||||
return new BigDecimal(value);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new JsonParseException("Cannot parse " + value + "; at path " + in.getPath(), e);
|
||||
throw new JsonParseException("Cannot parse " + value + "; at path " + in.getPreviousPath(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -72,30 +72,36 @@ public final class DateTypeAdapter extends TypeAdapter<Date> {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
return deserializeToDate(in.nextString());
|
||||
return deserializeToDate(in);
|
||||
}
|
||||
|
||||
private synchronized Date deserializeToDate(String json) {
|
||||
for (DateFormat dateFormat : dateFormats) {
|
||||
try {
|
||||
return dateFormat.parse(json);
|
||||
} catch (ParseException ignored) {}
|
||||
private Date deserializeToDate(JsonReader in) throws IOException {
|
||||
String s = in.nextString();
|
||||
synchronized (dateFormats) {
|
||||
for (DateFormat dateFormat : dateFormats) {
|
||||
try {
|
||||
return dateFormat.parse(s);
|
||||
} catch (ParseException ignored) {}
|
||||
}
|
||||
}
|
||||
try {
|
||||
return ISO8601Utils.parse(json, new ParsePosition(0));
|
||||
return ISO8601Utils.parse(s, new ParsePosition(0));
|
||||
} catch (ParseException e) {
|
||||
throw new JsonSyntaxException(json, e);
|
||||
throw new JsonSyntaxException("Failed parsing '" + s + "' as Date; at path " + in.getPreviousPath(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public synchronized void write(JsonWriter out, Date value) throws IOException {
|
||||
@Override public void write(JsonWriter out, Date value) throws IOException {
|
||||
if (value == null) {
|
||||
out.nullValue();
|
||||
return;
|
||||
}
|
||||
String dateFormatAsString = dateFormats.get(0).format(value);
|
||||
|
||||
DateFormat dateFormat = dateFormats.get(0);
|
||||
String dateFormatAsString;
|
||||
synchronized (dateFormats) {
|
||||
dateFormatAsString = dateFormat.format(value);
|
||||
}
|
||||
out.value(dateFormatAsString);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -130,10 +130,13 @@ public final class DefaultDateTypeAdapter<T extends Date> extends TypeAdapter<T>
|
||||
out.nullValue();
|
||||
return;
|
||||
}
|
||||
synchronized(dateFormats) {
|
||||
String dateFormatAsString = dateFormats.get(0).format(value);
|
||||
out.value(dateFormatAsString);
|
||||
|
||||
DateFormat dateFormat = dateFormats.get(0);
|
||||
String dateFormatAsString;
|
||||
synchronized (dateFormats) {
|
||||
dateFormatAsString = dateFormat.format(value);
|
||||
}
|
||||
out.value(dateFormatAsString);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -142,11 +145,12 @@ public final class DefaultDateTypeAdapter<T extends Date> extends TypeAdapter<T>
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
Date date = deserializeToDate(in.nextString());
|
||||
Date date = deserializeToDate(in);
|
||||
return dateType.deserialize(date);
|
||||
}
|
||||
|
||||
private Date deserializeToDate(String s) {
|
||||
private Date deserializeToDate(JsonReader in) throws IOException {
|
||||
String s = in.nextString();
|
||||
synchronized (dateFormats) {
|
||||
for (DateFormat dateFormat : dateFormats) {
|
||||
try {
|
||||
@ -158,7 +162,7 @@ public final class DefaultDateTypeAdapter<T extends Date> extends TypeAdapter<T>
|
||||
try {
|
||||
return ISO8601Utils.parse(s, new ParsePosition(0));
|
||||
} catch (ParseException e) {
|
||||
throw new JsonSyntaxException(s, e);
|
||||
throw new JsonSyntaxException("Failed parsing '" + s + "' as Date; at path " + in.getPreviousPath(), e);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -304,12 +304,19 @@ public final class JsonTreeReader extends JsonReader {
|
||||
stack[stackSize++] = newTop;
|
||||
}
|
||||
|
||||
@Override public String getPath() {
|
||||
private String getPath(boolean usePreviousPath) {
|
||||
StringBuilder result = new StringBuilder().append('$');
|
||||
for (int i = 0; i < stackSize; i++) {
|
||||
if (stack[i] instanceof JsonArray) {
|
||||
if (++i < stackSize && stack[i] instanceof Iterator) {
|
||||
result.append('[').append(pathIndices[i]).append(']');
|
||||
int pathIndex = pathIndices[i];
|
||||
// If index is last path element it points to next array element; have to decrement
|
||||
// `- 1` covers case where iterator for next element is on stack
|
||||
// `- 2` covers case where peek() already pushed next element onto stack
|
||||
if (usePreviousPath && pathIndex > 0 && (i == stackSize - 1 || i == stackSize - 2)) {
|
||||
pathIndex--;
|
||||
}
|
||||
result.append('[').append(pathIndex).append(']');
|
||||
}
|
||||
} else if (stack[i] instanceof JsonObject) {
|
||||
if (++i < stackSize && stack[i] instanceof Iterator) {
|
||||
@ -323,6 +330,14 @@ public final class JsonTreeReader extends JsonReader {
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
@Override public String getPreviousPath() {
|
||||
return getPath(true);
|
||||
}
|
||||
|
||||
@Override public String getPath() {
|
||||
return getPath(false);
|
||||
}
|
||||
|
||||
private String locationString() {
|
||||
return " at path " + getPath();
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ public final class NumberTypeAdapter extends TypeAdapter<Number> {
|
||||
case STRING:
|
||||
return toNumberStrategy.readNumber(in);
|
||||
default:
|
||||
throw new JsonSyntaxException("Expecting number, got: " + jsonToken);
|
||||
throw new JsonSyntaxException("Expecting number, got: " + jsonToken + "; at path " + in.getPath());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -92,22 +92,21 @@ public final class TypeAdapters {
|
||||
boolean set;
|
||||
switch (tokenType) {
|
||||
case NUMBER:
|
||||
set = in.nextInt() != 0;
|
||||
case STRING:
|
||||
int intValue = in.nextInt();
|
||||
if (intValue == 0) {
|
||||
set = false;
|
||||
} else if (intValue == 1) {
|
||||
set = true;
|
||||
} else {
|
||||
throw new JsonSyntaxException("Invalid bitset value " + intValue + ", expected 0 or 1; at path " + in.getPreviousPath());
|
||||
}
|
||||
break;
|
||||
case BOOLEAN:
|
||||
set = in.nextBoolean();
|
||||
break;
|
||||
case STRING:
|
||||
String stringValue = in.nextString();
|
||||
try {
|
||||
set = Integer.parseInt(stringValue) != 0;
|
||||
} catch (NumberFormatException e) {
|
||||
throw new JsonSyntaxException(
|
||||
"Error: Expecting: bitset number value (1, 0), Found: " + stringValue);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new JsonSyntaxException("Invalid bitset value type: " + tokenType);
|
||||
throw new JsonSyntaxException("Invalid bitset value type: " + tokenType + "; at path " + in.getPath());
|
||||
}
|
||||
if (set) {
|
||||
bitset.set(i);
|
||||
@ -178,12 +177,18 @@ public final class TypeAdapters {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
|
||||
int intValue;
|
||||
try {
|
||||
int intValue = in.nextInt();
|
||||
return (byte) intValue;
|
||||
intValue = in.nextInt();
|
||||
} catch (NumberFormatException e) {
|
||||
throw new JsonSyntaxException(e);
|
||||
}
|
||||
// Allow up to 255 to support unsigned values
|
||||
if (intValue > 255 || intValue < Byte.MIN_VALUE) {
|
||||
throw new JsonSyntaxException("Lossy conversion from " + intValue + " to byte; at path " + in.getPreviousPath());
|
||||
}
|
||||
return (byte) intValue;
|
||||
}
|
||||
@Override
|
||||
public void write(JsonWriter out, Number value) throws IOException {
|
||||
@ -201,11 +206,18 @@ public final class TypeAdapters {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
|
||||
int intValue;
|
||||
try {
|
||||
return (short) in.nextInt();
|
||||
intValue = in.nextInt();
|
||||
} catch (NumberFormatException e) {
|
||||
throw new JsonSyntaxException(e);
|
||||
}
|
||||
// Allow up to 65535 to support unsigned values
|
||||
if (intValue > 65535 || intValue < Short.MIN_VALUE) {
|
||||
throw new JsonSyntaxException("Lossy conversion from " + intValue + " to short; at path " + in.getPreviousPath());
|
||||
}
|
||||
return (short) intValue;
|
||||
}
|
||||
@Override
|
||||
public void write(JsonWriter out, Number value) throws IOException {
|
||||
@ -352,7 +364,7 @@ public final class TypeAdapters {
|
||||
}
|
||||
String str = in.nextString();
|
||||
if (str.length() != 1) {
|
||||
throw new JsonSyntaxException("Expecting character, got: " + str);
|
||||
throw new JsonSyntaxException("Expecting character, got: " + str + "; at " + in.getPreviousPath());
|
||||
}
|
||||
return str.charAt(0);
|
||||
}
|
||||
@ -391,10 +403,11 @@ public final class TypeAdapters {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
String s = in.nextString();
|
||||
try {
|
||||
return new BigDecimal(in.nextString());
|
||||
return new BigDecimal(s);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new JsonSyntaxException(e);
|
||||
throw new JsonSyntaxException("Failed parsing '" + s + "' as BigDecimal; at path " + in.getPreviousPath(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -409,10 +422,11 @@ public final class TypeAdapters {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
String s = in.nextString();
|
||||
try {
|
||||
return new BigInteger(in.nextString());
|
||||
return new BigInteger(s);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new JsonSyntaxException(e);
|
||||
throw new JsonSyntaxException("Failed parsing '" + s + "' as BigInteger; at path " + in.getPreviousPath(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@ -525,7 +539,12 @@ public final class TypeAdapters {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
return java.util.UUID.fromString(in.nextString());
|
||||
String s = in.nextString();
|
||||
try {
|
||||
return java.util.UUID.fromString(s);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new JsonSyntaxException("Failed parsing '" + s + "' as UUID; at path " + in.getPreviousPath(), e);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void write(JsonWriter out, UUID value) throws IOException {
|
||||
@ -538,7 +557,12 @@ public final class TypeAdapters {
|
||||
public static final TypeAdapter<Currency> CURRENCY = new TypeAdapter<Currency>() {
|
||||
@Override
|
||||
public Currency read(JsonReader in) throws IOException {
|
||||
return Currency.getInstance(in.nextString());
|
||||
String s = in.nextString();
|
||||
try {
|
||||
return Currency.getInstance(s);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new JsonSyntaxException("Failed parsing '" + s + "' as Currency; at path " + in.getPreviousPath(), e);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void write(JsonWriter out, Currency value) throws IOException {
|
||||
@ -866,7 +890,7 @@ public final class TypeAdapters {
|
||||
T1 result = typeAdapter.read(in);
|
||||
if (result != null && !requestedType.isInstance(result)) {
|
||||
throw new JsonSyntaxException("Expected a " + requestedType.getName()
|
||||
+ " but was " + result.getClass().getName());
|
||||
+ " but was " + result.getClass().getName() + "; at path " + in.getPreviousPath());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ import java.io.IOException;
|
||||
import java.text.DateFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* Adapter for java.sql.Date. Although this class appears stateless, it is not.
|
||||
@ -50,21 +51,33 @@ final class SqlDateTypeAdapter extends TypeAdapter<java.sql.Date> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized java.sql.Date read(JsonReader in) throws IOException {
|
||||
public java.sql.Date read(JsonReader in) throws IOException {
|
||||
if (in.peek() == JsonToken.NULL) {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
String s = in.nextString();
|
||||
try {
|
||||
final long utilDate = format.parse(in.nextString()).getTime();
|
||||
return new java.sql.Date(utilDate);
|
||||
Date utilDate;
|
||||
synchronized (this) {
|
||||
utilDate = format.parse(s);
|
||||
}
|
||||
return new java.sql.Date(utilDate.getTime());
|
||||
} catch (ParseException e) {
|
||||
throw new JsonSyntaxException(e);
|
||||
throw new JsonSyntaxException("Failed parsing '" + s + "' as SQL Date; at path " + in.getPreviousPath(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void write(JsonWriter out, java.sql.Date value) throws IOException {
|
||||
out.value(value == null ? null : format.format(value));
|
||||
public void write(JsonWriter out, java.sql.Date value) throws IOException {
|
||||
if (value == null) {
|
||||
out.nullValue();
|
||||
return;
|
||||
}
|
||||
String dateString;
|
||||
synchronized (this) {
|
||||
dateString = format.format(value);
|
||||
}
|
||||
out.value(dateString);
|
||||
}
|
||||
}
|
||||
|
@ -50,20 +50,31 @@ final class SqlTimeTypeAdapter extends TypeAdapter<Time> {
|
||||
private SqlTimeTypeAdapter() {
|
||||
}
|
||||
|
||||
@Override public synchronized Time read(JsonReader in) throws IOException {
|
||||
@Override public Time read(JsonReader in) throws IOException {
|
||||
if (in.peek() == JsonToken.NULL) {
|
||||
in.nextNull();
|
||||
return null;
|
||||
}
|
||||
String s = in.nextString();
|
||||
try {
|
||||
Date date = format.parse(in.nextString());
|
||||
return new Time(date.getTime());
|
||||
synchronized (this) {
|
||||
Date date = format.parse(s);
|
||||
return new Time(date.getTime());
|
||||
}
|
||||
} catch (ParseException e) {
|
||||
throw new JsonSyntaxException(e);
|
||||
throw new JsonSyntaxException("Failed parsing '" + s + "' as SQL Time; at path " + in.getPreviousPath(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public synchronized void write(JsonWriter out, Time value) throws IOException {
|
||||
out.value(value == null ? null : format.format(value));
|
||||
@Override public void write(JsonWriter out, Time value) throws IOException {
|
||||
if (value == null) {
|
||||
out.nullValue();
|
||||
return;
|
||||
}
|
||||
String timeString;
|
||||
synchronized (this) {
|
||||
timeString = format.format(value);
|
||||
}
|
||||
out.value(timeString);
|
||||
}
|
||||
}
|
||||
|
@ -1085,7 +1085,7 @@ public class JsonReader implements Closeable {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
String result = (null == builder) ? new String(buffer, pos, i) : builder.append(buffer, pos, i).toString();
|
||||
pos += i;
|
||||
return result;
|
||||
@ -1454,19 +1454,19 @@ public class JsonReader implements Closeable {
|
||||
return " at line " + line + " column " + column + " path " + getPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a <a href="http://goessner.net/articles/JsonPath/">JsonPath</a> to
|
||||
* the current location in the JSON value.
|
||||
*/
|
||||
public String getPath() {
|
||||
private String getPath(boolean usePreviousPath) {
|
||||
StringBuilder result = new StringBuilder().append('$');
|
||||
for (int i = 0, size = stackSize; i < size; i++) {
|
||||
for (int i = 0; i < stackSize; i++) {
|
||||
switch (stack[i]) {
|
||||
case JsonScope.EMPTY_ARRAY:
|
||||
case JsonScope.NONEMPTY_ARRAY:
|
||||
result.append('[').append(pathIndices[i]).append(']');
|
||||
int pathIndex = pathIndices[i];
|
||||
// If index is last path element it points to next array element; have to decrement
|
||||
if (usePreviousPath && pathIndex > 0 && i == stackSize - 1) {
|
||||
pathIndex--;
|
||||
}
|
||||
result.append('[').append(pathIndex).append(']');
|
||||
break;
|
||||
|
||||
case JsonScope.EMPTY_OBJECT:
|
||||
case JsonScope.DANGLING_NAME:
|
||||
case JsonScope.NONEMPTY_OBJECT:
|
||||
@ -1475,7 +1475,6 @@ public class JsonReader implements Closeable {
|
||||
result.append(pathNames[i]);
|
||||
}
|
||||
break;
|
||||
|
||||
case JsonScope.NONEMPTY_DOCUMENT:
|
||||
case JsonScope.EMPTY_DOCUMENT:
|
||||
case JsonScope.CLOSED:
|
||||
@ -1485,6 +1484,41 @@ public class JsonReader implements Closeable {
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a <a href="https://goessner.net/articles/JsonPath/">JsonPath</a>
|
||||
* in <i>dot-notation</i> to the previous (or current) location in the JSON document:
|
||||
* <ul>
|
||||
* <li>For JSON arrays the path points to the index of the previous element.<br>
|
||||
* If no element has been consumed yet it uses the index 0 (even if there are no elements).</li>
|
||||
* <li>For JSON objects the path points to the last property, or to the current
|
||||
* property if its value has not been consumed yet.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>This method can be useful to add additional context to exception messages
|
||||
* <i>after</i> a value has been consumed.
|
||||
*/
|
||||
public String getPreviousPath() {
|
||||
return getPath(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a <a href="https://goessner.net/articles/JsonPath/">JsonPath</a>
|
||||
* in <i>dot-notation</i> to the next (or current) location in the JSON document:
|
||||
* <ul>
|
||||
* <li>For JSON arrays the path points to the index of the next element (even
|
||||
* if there are no further elements).</li>
|
||||
* <li>For JSON objects the path points to the last property, or to the current
|
||||
* property if its value has not been consumed yet.</li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>This method can be useful to add additional context to exception messages
|
||||
* <i>before</i> a value is consumed, for example when the {@linkplain #peek() peeked}
|
||||
* token is unexpected.
|
||||
*/
|
||||
public String getPath() {
|
||||
return getPath(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unescapes the character identified by the character or characters that
|
||||
* immediately follow a backslash. The backslash '\' should have already
|
||||
@ -1546,11 +1580,11 @@ public class JsonReader implements Closeable {
|
||||
case '\'':
|
||||
case '"':
|
||||
case '\\':
|
||||
case '/':
|
||||
return escaped;
|
||||
case '/':
|
||||
return escaped;
|
||||
default:
|
||||
// throw error when none of the above cases are matched
|
||||
throw syntaxError("Invalid escape sequence");
|
||||
// throw error when none of the above cases are matched
|
||||
throw syntaxError("Invalid escape sequence");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -332,6 +332,20 @@ public class DefaultTypeAdaptersTest extends TestCase {
|
||||
|
||||
json = "[true,false,true,true,true,true,false,false,true,false,false]";
|
||||
assertEquals(expected, gson.fromJson(json, BitSet.class));
|
||||
|
||||
try {
|
||||
gson.fromJson("[1, []]", BitSet.class);
|
||||
fail();
|
||||
} catch (JsonSyntaxException e) {
|
||||
assertEquals("Invalid bitset value type: BEGIN_ARRAY; at path $[1]", e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
gson.fromJson("[1, 2]", BitSet.class);
|
||||
fail();
|
||||
} catch (JsonSyntaxException e) {
|
||||
assertEquals("Invalid bitset value 2, expected 0 or 1; at path $[1]", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testDefaultDateSerialization() {
|
||||
@ -567,7 +581,7 @@ public class DefaultTypeAdaptersTest extends TestCase {
|
||||
gson.fromJson("\"abc\"", JsonObject.class);
|
||||
fail();
|
||||
} catch (JsonSyntaxException expected) {
|
||||
assertEquals("Expected a com.google.gson.JsonObject but was com.google.gson.JsonPrimitive",
|
||||
assertEquals("Expected a com.google.gson.JsonObject but was com.google.gson.JsonPrimitive; at path $",
|
||||
expected.getMessage());
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
package com.google.gson.functional;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
@ -63,16 +65,75 @@ public class PrimitiveTest extends TestCase {
|
||||
assertEquals("1", gson.toJson(1, Byte.class));
|
||||
}
|
||||
|
||||
public void testByteDeserialization() {
|
||||
Byte boxed = gson.fromJson("1", Byte.class);
|
||||
assertEquals(1, (byte)boxed);
|
||||
byte primitive = gson.fromJson("1", byte.class);
|
||||
assertEquals(1, primitive);
|
||||
|
||||
byte[] bytes = gson.fromJson("[-128, 0, 127, 255]", byte[].class);
|
||||
assertArrayEquals(new byte[] {-128, 0, 127, -1}, bytes);
|
||||
}
|
||||
|
||||
public void testByteDeserializationLossy() {
|
||||
try {
|
||||
gson.fromJson("-129", byte.class);
|
||||
fail();
|
||||
} catch (JsonSyntaxException e) {
|
||||
assertEquals("Lossy conversion from -129 to byte; at path $", e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
gson.fromJson("256", byte.class);
|
||||
fail();
|
||||
} catch (JsonSyntaxException e) {
|
||||
assertEquals("Lossy conversion from 256 to byte; at path $", e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
gson.fromJson("2147483648", byte.class);
|
||||
fail();
|
||||
} catch (JsonSyntaxException e) {
|
||||
assertEquals("java.lang.NumberFormatException: Expected an int but was 2147483648 at line 1 column 11 path $", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testShortSerialization() {
|
||||
assertEquals("1", gson.toJson(1, short.class));
|
||||
assertEquals("1", gson.toJson(1, Short.class));
|
||||
}
|
||||
|
||||
public void testByteDeserialization() {
|
||||
Byte target = gson.fromJson("1", Byte.class);
|
||||
assertEquals(1, (byte)target);
|
||||
byte primitive = gson.fromJson("1", byte.class);
|
||||
public void testShortDeserialization() {
|
||||
Short boxed = gson.fromJson("1", Short.class);
|
||||
assertEquals(1, (short)boxed);
|
||||
short primitive = gson.fromJson("1", short.class);
|
||||
assertEquals(1, primitive);
|
||||
|
||||
short[] shorts = gson.fromJson("[-32768, 0, 32767, 65535]", short[].class);
|
||||
assertArrayEquals(new short[] {-32768, 0, 32767, -1}, shorts);
|
||||
}
|
||||
|
||||
public void testShortDeserializationLossy() {
|
||||
try {
|
||||
gson.fromJson("-32769", short.class);
|
||||
fail();
|
||||
} catch (JsonSyntaxException e) {
|
||||
assertEquals("Lossy conversion from -32769 to short; at path $", e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
gson.fromJson("65536", short.class);
|
||||
fail();
|
||||
} catch (JsonSyntaxException e) {
|
||||
assertEquals("Lossy conversion from 65536 to short; at path $", e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
gson.fromJson("2147483648", short.class);
|
||||
fail();
|
||||
} catch (JsonSyntaxException e) {
|
||||
assertEquals("java.lang.NumberFormatException: Expected an int but was 2147483648 at line 1 column 11 path $", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testPrimitiveIntegerAutoboxedInASingleElementArraySerialization() {
|
||||
|
@ -46,110 +46,154 @@ public class JsonReaderPathTest {
|
||||
|
||||
@Test public void path() throws IOException {
|
||||
JsonReader reader = factory.create("{\"a\":[2,true,false,null,\"b\",{\"c\":\"d\"},[3]]}");
|
||||
assertEquals("$", reader.getPreviousPath());
|
||||
assertEquals("$", reader.getPath());
|
||||
reader.beginObject();
|
||||
assertEquals("$.", reader.getPreviousPath());
|
||||
assertEquals("$.", reader.getPath());
|
||||
reader.nextName();
|
||||
assertEquals("$.a", reader.getPreviousPath());
|
||||
assertEquals("$.a", reader.getPath());
|
||||
reader.beginArray();
|
||||
assertEquals("$.a[0]", reader.getPreviousPath());
|
||||
assertEquals("$.a[0]", reader.getPath());
|
||||
reader.nextInt();
|
||||
assertEquals("$.a[0]", reader.getPreviousPath());
|
||||
assertEquals("$.a[1]", reader.getPath());
|
||||
reader.nextBoolean();
|
||||
assertEquals("$.a[1]", reader.getPreviousPath());
|
||||
assertEquals("$.a[2]", reader.getPath());
|
||||
reader.nextBoolean();
|
||||
assertEquals("$.a[2]", reader.getPreviousPath());
|
||||
assertEquals("$.a[3]", reader.getPath());
|
||||
reader.nextNull();
|
||||
assertEquals("$.a[3]", reader.getPreviousPath());
|
||||
assertEquals("$.a[4]", reader.getPath());
|
||||
reader.nextString();
|
||||
assertEquals("$.a[4]", reader.getPreviousPath());
|
||||
assertEquals("$.a[5]", reader.getPath());
|
||||
reader.beginObject();
|
||||
assertEquals("$.a[5].", reader.getPreviousPath());
|
||||
assertEquals("$.a[5].", reader.getPath());
|
||||
reader.nextName();
|
||||
assertEquals("$.a[5].c", reader.getPreviousPath());
|
||||
assertEquals("$.a[5].c", reader.getPath());
|
||||
reader.nextString();
|
||||
assertEquals("$.a[5].c", reader.getPreviousPath());
|
||||
assertEquals("$.a[5].c", reader.getPath());
|
||||
reader.endObject();
|
||||
assertEquals("$.a[5]", reader.getPreviousPath());
|
||||
assertEquals("$.a[6]", reader.getPath());
|
||||
reader.beginArray();
|
||||
assertEquals("$.a[6][0]", reader.getPreviousPath());
|
||||
assertEquals("$.a[6][0]", reader.getPath());
|
||||
reader.nextInt();
|
||||
assertEquals("$.a[6][0]", reader.getPreviousPath());
|
||||
assertEquals("$.a[6][1]", reader.getPath());
|
||||
reader.endArray();
|
||||
assertEquals("$.a[6]", reader.getPreviousPath());
|
||||
assertEquals("$.a[7]", reader.getPath());
|
||||
reader.endArray();
|
||||
assertEquals("$.a", reader.getPreviousPath());
|
||||
assertEquals("$.a", reader.getPath());
|
||||
reader.endObject();
|
||||
assertEquals("$", reader.getPreviousPath());
|
||||
assertEquals("$", reader.getPath());
|
||||
}
|
||||
|
||||
@Test public void objectPath() throws IOException {
|
||||
JsonReader reader = factory.create("{\"a\":1,\"b\":2}");
|
||||
assertEquals("$", reader.getPreviousPath());
|
||||
assertEquals("$", reader.getPath());
|
||||
|
||||
reader.peek();
|
||||
assertEquals("$", reader.getPreviousPath());
|
||||
assertEquals("$", reader.getPath());
|
||||
reader.beginObject();
|
||||
assertEquals("$.", reader.getPreviousPath());
|
||||
assertEquals("$.", reader.getPath());
|
||||
|
||||
reader.peek();
|
||||
assertEquals("$.", reader.getPreviousPath());
|
||||
assertEquals("$.", reader.getPath());
|
||||
reader.nextName();
|
||||
assertEquals("$.a", reader.getPreviousPath());
|
||||
assertEquals("$.a", reader.getPath());
|
||||
|
||||
reader.peek();
|
||||
assertEquals("$.a", reader.getPreviousPath());
|
||||
assertEquals("$.a", reader.getPath());
|
||||
reader.nextInt();
|
||||
assertEquals("$.a", reader.getPreviousPath());
|
||||
assertEquals("$.a", reader.getPath());
|
||||
|
||||
reader.peek();
|
||||
assertEquals("$.a", reader.getPreviousPath());
|
||||
assertEquals("$.a", reader.getPath());
|
||||
reader.nextName();
|
||||
assertEquals("$.b", reader.getPreviousPath());
|
||||
assertEquals("$.b", reader.getPath());
|
||||
|
||||
reader.peek();
|
||||
assertEquals("$.b", reader.getPreviousPath());
|
||||
assertEquals("$.b", reader.getPath());
|
||||
reader.nextInt();
|
||||
assertEquals("$.b", reader.getPreviousPath());
|
||||
assertEquals("$.b", reader.getPath());
|
||||
|
||||
reader.peek();
|
||||
assertEquals("$.b", reader.getPreviousPath());
|
||||
assertEquals("$.b", reader.getPath());
|
||||
reader.endObject();
|
||||
assertEquals("$", reader.getPreviousPath());
|
||||
assertEquals("$", reader.getPath());
|
||||
|
||||
reader.peek();
|
||||
assertEquals("$", reader.getPreviousPath());
|
||||
assertEquals("$", reader.getPath());
|
||||
reader.close();
|
||||
assertEquals("$", reader.getPreviousPath());
|
||||
assertEquals("$", reader.getPath());
|
||||
}
|
||||
|
||||
@Test public void arrayPath() throws IOException {
|
||||
JsonReader reader = factory.create("[1,2]");
|
||||
assertEquals("$", reader.getPreviousPath());
|
||||
assertEquals("$", reader.getPath());
|
||||
|
||||
reader.peek();
|
||||
assertEquals("$", reader.getPreviousPath());
|
||||
assertEquals("$", reader.getPath());
|
||||
reader.beginArray();
|
||||
assertEquals("$[0]", reader.getPreviousPath());
|
||||
assertEquals("$[0]", reader.getPath());
|
||||
|
||||
reader.peek();
|
||||
assertEquals("$[0]", reader.getPreviousPath());
|
||||
assertEquals("$[0]", reader.getPath());
|
||||
reader.nextInt();
|
||||
assertEquals("$[0]", reader.getPreviousPath());
|
||||
assertEquals("$[1]", reader.getPath());
|
||||
|
||||
reader.peek();
|
||||
assertEquals("$[0]", reader.getPreviousPath());
|
||||
assertEquals("$[1]", reader.getPath());
|
||||
reader.nextInt();
|
||||
assertEquals("$[1]", reader.getPreviousPath());
|
||||
assertEquals("$[2]", reader.getPath());
|
||||
|
||||
reader.peek();
|
||||
assertEquals("$[1]", reader.getPreviousPath());
|
||||
assertEquals("$[2]", reader.getPath());
|
||||
reader.endArray();
|
||||
assertEquals("$", reader.getPreviousPath());
|
||||
assertEquals("$", reader.getPath());
|
||||
|
||||
reader.peek();
|
||||
assertEquals("$", reader.getPreviousPath());
|
||||
assertEquals("$", reader.getPath());
|
||||
reader.close();
|
||||
assertEquals("$", reader.getPreviousPath());
|
||||
assertEquals("$", reader.getPath());
|
||||
}
|
||||
|
||||
@ -160,9 +204,11 @@ public class JsonReaderPathTest {
|
||||
reader.setLenient(true);
|
||||
reader.beginArray();
|
||||
reader.endArray();
|
||||
assertEquals("$", reader.getPreviousPath());
|
||||
assertEquals("$", reader.getPath());
|
||||
reader.beginArray();
|
||||
reader.endArray();
|
||||
assertEquals("$", reader.getPreviousPath());
|
||||
assertEquals("$", reader.getPath());
|
||||
}
|
||||
|
||||
@ -171,6 +217,7 @@ public class JsonReaderPathTest {
|
||||
reader.beginArray();
|
||||
reader.skipValue();
|
||||
reader.skipValue();
|
||||
assertEquals("$[1]", reader.getPreviousPath());
|
||||
assertEquals("$[2]", reader.getPath());
|
||||
}
|
||||
|
||||
@ -178,17 +225,21 @@ public class JsonReaderPathTest {
|
||||
JsonReader reader = factory.create("{\"a\":1}");
|
||||
reader.beginObject();
|
||||
reader.skipValue();
|
||||
assertEquals("$.null", reader.getPreviousPath());
|
||||
assertEquals("$.null", reader.getPath());
|
||||
}
|
||||
|
||||
@Test public void skipObjectValues() throws IOException {
|
||||
JsonReader reader = factory.create("{\"a\":1,\"b\":2}");
|
||||
reader.beginObject();
|
||||
assertEquals("$.", reader.getPreviousPath());
|
||||
assertEquals("$.", reader.getPath());
|
||||
reader.nextName();
|
||||
reader.skipValue();
|
||||
assertEquals("$.null", reader.getPreviousPath());
|
||||
assertEquals("$.null", reader.getPath());
|
||||
reader.nextName();
|
||||
assertEquals("$.b", reader.getPreviousPath());
|
||||
assertEquals("$.b", reader.getPath());
|
||||
}
|
||||
|
||||
@ -196,46 +247,63 @@ public class JsonReaderPathTest {
|
||||
JsonReader reader = factory.create("[[1,2,3],4]");
|
||||
reader.beginArray();
|
||||
reader.skipValue();
|
||||
assertEquals("$[0]", reader.getPreviousPath());
|
||||
assertEquals("$[1]", reader.getPath());
|
||||
}
|
||||
|
||||
@Test public void arrayOfObjects() throws IOException {
|
||||
JsonReader reader = factory.create("[{},{},{}]");
|
||||
reader.beginArray();
|
||||
assertEquals("$[0]", reader.getPreviousPath());
|
||||
assertEquals("$[0]", reader.getPath());
|
||||
reader.beginObject();
|
||||
assertEquals("$[0].", reader.getPreviousPath());
|
||||
assertEquals("$[0].", reader.getPath());
|
||||
reader.endObject();
|
||||
assertEquals("$[0]", reader.getPreviousPath());
|
||||
assertEquals("$[1]", reader.getPath());
|
||||
reader.beginObject();
|
||||
assertEquals("$[1].", reader.getPreviousPath());
|
||||
assertEquals("$[1].", reader.getPath());
|
||||
reader.endObject();
|
||||
assertEquals("$[1]", reader.getPreviousPath());
|
||||
assertEquals("$[2]", reader.getPath());
|
||||
reader.beginObject();
|
||||
assertEquals("$[2].", reader.getPreviousPath());
|
||||
assertEquals("$[2].", reader.getPath());
|
||||
reader.endObject();
|
||||
assertEquals("$[2]", reader.getPreviousPath());
|
||||
assertEquals("$[3]", reader.getPath());
|
||||
reader.endArray();
|
||||
assertEquals("$", reader.getPreviousPath());
|
||||
assertEquals("$", reader.getPath());
|
||||
}
|
||||
|
||||
@Test public void arrayOfArrays() throws IOException {
|
||||
JsonReader reader = factory.create("[[],[],[]]");
|
||||
reader.beginArray();
|
||||
assertEquals("$[0]", reader.getPreviousPath());
|
||||
assertEquals("$[0]", reader.getPath());
|
||||
reader.beginArray();
|
||||
assertEquals("$[0][0]", reader.getPreviousPath());
|
||||
assertEquals("$[0][0]", reader.getPath());
|
||||
reader.endArray();
|
||||
assertEquals("$[0]", reader.getPreviousPath());
|
||||
assertEquals("$[1]", reader.getPath());
|
||||
reader.beginArray();
|
||||
assertEquals("$[1][0]", reader.getPreviousPath());
|
||||
assertEquals("$[1][0]", reader.getPath());
|
||||
reader.endArray();
|
||||
assertEquals("$[1]", reader.getPreviousPath());
|
||||
assertEquals("$[2]", reader.getPath());
|
||||
reader.beginArray();
|
||||
assertEquals("$[2][0]", reader.getPreviousPath());
|
||||
assertEquals("$[2][0]", reader.getPath());
|
||||
reader.endArray();
|
||||
assertEquals("$[2]", reader.getPreviousPath());
|
||||
assertEquals("$[3]", reader.getPath());
|
||||
reader.endArray();
|
||||
assertEquals("$", reader.getPreviousPath());
|
||||
assertEquals("$", reader.getPath());
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user