Several breaking changes

This commit is contained in:
Johannes Frohnmeyer 2022-05-17 21:20:10 +02:00
parent ccf30b23e8
commit dc4e61ac7b
Signed by: Johannes
GPG Key ID: E76429612C2929F4
47 changed files with 472 additions and 310 deletions

1
.gitignore vendored
View File

@ -20,3 +20,4 @@ build
.DS_Store .DS_Store
examples/android-proguard-example/gen examples/android-proguard-example/gen
.attach_pid*

View File

@ -1,7 +1,17 @@
# About this fork # About this fork
This fork of Gson adds support for writing comments in JsonWriter. This fork of Gson adds several features which were originally denied due to Gson's maintenance status.
To do this, JsonWriter and CommentsTest were adjusted. Among them are:
- support for writing comments
- collections with single entries without array syntax (`"single entry"` can become a `List` or array)
- stricter leniency enforcement from the main Gson class (`toJson`, `fromJson` will respect the choice)
- slightly better error messages
- skipping empty entries in arrays (`["one",, "two",]`)
- optionally omitting quotes around entry names like in Json5
- support for hexadecimal integers
This means the only thing lacking for Json5 support is trailing commas in objects
Please be aware that I also increased the minimum java version to 11 Please be aware that I also increased the minimum java version to 11
To use this, add the following: To use this, add the following:
```groovy ```groovy

View File

@ -35,12 +35,7 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicLongArray; import java.util.concurrent.atomic.AtomicLongArray;
import com.google.gson.internal.ConstructorConstructor; import com.google.gson.internal.*;
import com.google.gson.internal.Excluder;
import com.google.gson.internal.GsonBuildConfig;
import com.google.gson.internal.LazilyParsedNumber;
import com.google.gson.internal.Primitives;
import com.google.gson.internal.Streams;
import com.google.gson.internal.bind.ArrayTypeAdapter; import com.google.gson.internal.bind.ArrayTypeAdapter;
import com.google.gson.internal.bind.CollectionTypeAdapterFactory; import com.google.gson.internal.bind.CollectionTypeAdapterFactory;
import com.google.gson.internal.bind.DateTypeAdapter; import com.google.gson.internal.bind.DateTypeAdapter;
@ -104,23 +99,6 @@ import com.google.gson.stream.MalformedJsonException;
* @author Jesse Wilson * @author Jesse Wilson
*/ */
public final class Gson { public final class Gson {
static final boolean DEFAULT_JSON_NON_EXECUTABLE = false;
static final boolean DEFAULT_LENIENT = false;
static final boolean DEFAULT_PRETTY_PRINT = false;
static final boolean DEFAULT_ESCAPE_HTML = true;
static final boolean DEFAULT_SERIALIZE_NULLS = false;
static final boolean DEFAULT_COMPLEX_MAP_KEYS = false;
static final boolean DEFAULT_DUPLICATE_MAP_KEYS = false;
static final boolean DEFAULT_SPECIALIZE_FLOAT_VALUES = false;
static final boolean DEFAULT_USE_JDK_UNSAFE = true;
static final String DEFAULT_DATE_PATTERN = null;
static final FieldNamingStrategy DEFAULT_FIELD_NAMING_STRATEGY = FieldNamingPolicy.IDENTITY;
static final ToNumberStrategy DEFAULT_OBJECT_TO_NUMBER_STRATEGY = ToNumberPolicy.DOUBLE;
static final ToNumberStrategy DEFAULT_NUMBER_TO_NUMBER_STRATEGY = ToNumberPolicy.LAZILY_PARSED_NUMBER;
private static final TypeToken<?> NULL_KEY_SURROGATE = TypeToken.get(Object.class);
private static final String JSON_NON_EXECUTABLE_PREFIX = ")]}'\n";
/** /**
* This thread local guards against reentrant calls to getAdapter(). In * This thread local guards against reentrant calls to getAdapter(). In
* certain object graphs, creating an adapter for a type may recursively * certain object graphs, creating an adapter for a type may recursively
@ -148,6 +126,7 @@ public final class Gson {
final boolean htmlSafe; final boolean htmlSafe;
final boolean prettyPrinting; final boolean prettyPrinting;
final boolean lenient; final boolean lenient;
final boolean omitQuotes;
final boolean serializeSpecialFloatingPointValues; final boolean serializeSpecialFloatingPointValues;
final boolean useJdkUnsafe; final boolean useJdkUnsafe;
final String datePattern; final String datePattern;
@ -195,21 +174,21 @@ public final class Gson {
* </ul> * </ul>
*/ */
public Gson() { public Gson() {
this(Excluder.DEFAULT, DEFAULT_FIELD_NAMING_STRATEGY, this(Excluder.DEFAULT, DefaultConfig.DEFAULT_FIELD_NAMING_STRATEGY,
Collections.<Type, InstanceCreator<?>>emptyMap(), DEFAULT_SERIALIZE_NULLS, Collections.<Type, InstanceCreator<?>>emptyMap(), DefaultConfig.DEFAULT_SERIALIZE_NULLS,
DEFAULT_COMPLEX_MAP_KEYS, DEFAULT_DUPLICATE_MAP_KEYS, DEFAULT_JSON_NON_EXECUTABLE, DEFAULT_ESCAPE_HTML, DefaultConfig.DEFAULT_COMPLEX_MAP_KEYS, DefaultConfig.DEFAULT_DUPLICATE_MAP_KEYS, DefaultConfig.DEFAULT_JSON_NON_EXECUTABLE, DefaultConfig.DEFAULT_ESCAPE_HTML,
DEFAULT_PRETTY_PRINT, DEFAULT_LENIENT, DEFAULT_SPECIALIZE_FLOAT_VALUES, DefaultConfig.DEFAULT_PRETTY_PRINT, true, DefaultConfig.DEFAULT_OMIT_QUOTES, DefaultConfig.DEFAULT_SPECIALIZE_FLOAT_VALUES,
DEFAULT_USE_JDK_UNSAFE, DefaultConfig.DEFAULT_USE_JDK_UNSAFE,
LongSerializationPolicy.DEFAULT, DEFAULT_DATE_PATTERN, DateFormat.DEFAULT, DateFormat.DEFAULT, LongSerializationPolicy.DEFAULT, DefaultConfig.DEFAULT_DATE_PATTERN, DateFormat.DEFAULT, DateFormat.DEFAULT,
Collections.<TypeAdapterFactory>emptyList(), Collections.<TypeAdapterFactory>emptyList(), Collections.<TypeAdapterFactory>emptyList(), Collections.<TypeAdapterFactory>emptyList(),
Collections.<TypeAdapterFactory>emptyList(), DEFAULT_OBJECT_TO_NUMBER_STRATEGY, DEFAULT_NUMBER_TO_NUMBER_STRATEGY, Collections.<TypeAdapterFactory>emptyList(), DefaultConfig.DEFAULT_OBJECT_TO_NUMBER_STRATEGY, DefaultConfig.DEFAULT_NUMBER_TO_NUMBER_STRATEGY,
Collections.<ReflectionAccessFilter>emptyList()); Collections.<ReflectionAccessFilter>emptyList());
} }
Gson(Excluder excluder, FieldNamingStrategy fieldNamingStrategy, Gson(Excluder excluder, FieldNamingStrategy fieldNamingStrategy,
Map<Type, InstanceCreator<?>> instanceCreators, boolean serializeNulls, Map<Type, InstanceCreator<?>> instanceCreators, boolean serializeNulls,
boolean complexMapKeySerialization, boolean duplicateMapKeyDeserialization, boolean generateNonExecutableGson, boolean htmlSafe, boolean complexMapKeySerialization, boolean duplicateMapKeyDeserialization, boolean generateNonExecutableGson, boolean htmlSafe,
boolean prettyPrinting, boolean lenient, boolean serializeSpecialFloatingPointValues, boolean prettyPrinting, boolean lenient, boolean omitQuotes, boolean serializeSpecialFloatingPointValues,
boolean useJdkUnsafe, boolean useJdkUnsafe,
LongSerializationPolicy longSerializationPolicy, String datePattern, int dateStyle, LongSerializationPolicy longSerializationPolicy, String datePattern, int dateStyle,
int timeStyle, List<TypeAdapterFactory> builderFactories, int timeStyle, List<TypeAdapterFactory> builderFactories,
@ -228,6 +207,7 @@ public final class Gson {
this.htmlSafe = htmlSafe; this.htmlSafe = htmlSafe;
this.prettyPrinting = prettyPrinting; this.prettyPrinting = prettyPrinting;
this.lenient = lenient; this.lenient = lenient;
this.omitQuotes = omitQuotes;
this.serializeSpecialFloatingPointValues = serializeSpecialFloatingPointValues; this.serializeSpecialFloatingPointValues = serializeSpecialFloatingPointValues;
this.useJdkUnsafe = useJdkUnsafe; this.useJdkUnsafe = useJdkUnsafe;
this.longSerializationPolicy = longSerializationPolicy; this.longSerializationPolicy = longSerializationPolicy;
@ -481,7 +461,7 @@ public final class Gson {
*/ */
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) { public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {
TypeAdapter<?> cached = typeTokenCache.get(type == null ? NULL_KEY_SURROGATE : type); TypeAdapter<?> cached = typeTokenCache.get(type == null ? DefaultConfig.NULL_KEY_SURROGATE : type);
if (cached != null) { if (cached != null) {
return (TypeAdapter<T>) cached; return (TypeAdapter<T>) cached;
} }
@ -745,7 +725,9 @@ public final class Gson {
public void toJson(Object src, Type typeOfSrc, JsonWriter writer) throws JsonIOException { public void toJson(Object src, Type typeOfSrc, JsonWriter writer) throws JsonIOException {
TypeAdapter<?> adapter = getAdapter(TypeToken.get(typeOfSrc)); TypeAdapter<?> adapter = getAdapter(TypeToken.get(typeOfSrc));
boolean oldLenient = writer.isLenient(); boolean oldLenient = writer.isLenient();
writer.setLenient(true); writer.setLenient(lenient);
boolean oldOmitQuotes = writer.getOmitQuotes();
writer.setOmitQuotes(omitQuotes);
boolean oldHtmlSafe = writer.isHtmlSafe(); boolean oldHtmlSafe = writer.isHtmlSafe();
writer.setHtmlSafe(htmlSafe); writer.setHtmlSafe(htmlSafe);
boolean oldSerializeNulls = writer.getSerializeNulls(); boolean oldSerializeNulls = writer.getSerializeNulls();
@ -760,6 +742,7 @@ public final class Gson {
throw error; throw error;
} finally { } finally {
writer.setLenient(oldLenient); writer.setLenient(oldLenient);
writer.setOmitQuotes(oldOmitQuotes);
writer.setHtmlSafe(oldHtmlSafe); writer.setHtmlSafe(oldHtmlSafe);
writer.setSerializeNulls(oldSerializeNulls); writer.setSerializeNulls(oldSerializeNulls);
} }
@ -804,12 +787,13 @@ public final class Gson {
* <li>{@link GsonBuilder#generateNonExecutableJson()}</li> * <li>{@link GsonBuilder#generateNonExecutableJson()}</li>
* <li>{@link GsonBuilder#serializeNulls()}</li> * <li>{@link GsonBuilder#serializeNulls()}</li>
* <li>{@link GsonBuilder#setLenient()}</li> * <li>{@link GsonBuilder#setLenient()}</li>
* <li>{@link GsonBuilder#setOmitQuotes()}</li>
* <li>{@link GsonBuilder#setPrettyPrinting()}</li> * <li>{@link GsonBuilder#setPrettyPrinting()}</li>
* </ul> * </ul>
*/ */
public JsonWriter newJsonWriter(Writer writer) throws IOException { public JsonWriter newJsonWriter(Writer writer) throws IOException {
if (generateNonExecutableJson) { if (generateNonExecutableJson) {
writer.write(JSON_NON_EXECUTABLE_PREFIX); writer.write(DefaultConfig.JSON_NON_EXECUTABLE_PREFIX);
} }
JsonWriter jsonWriter = new JsonWriter(writer); JsonWriter jsonWriter = new JsonWriter(writer);
if (prettyPrinting) { if (prettyPrinting) {
@ -817,6 +801,7 @@ public final class Gson {
} }
jsonWriter.setHtmlSafe(htmlSafe); jsonWriter.setHtmlSafe(htmlSafe);
jsonWriter.setLenient(lenient); jsonWriter.setLenient(lenient);
jsonWriter.setOmitQuotes(omitQuotes);
jsonWriter.setSerializeNulls(serializeNulls); jsonWriter.setSerializeNulls(serializeNulls);
return jsonWriter; return jsonWriter;
} }
@ -841,7 +826,9 @@ public final class Gson {
*/ */
public void toJson(JsonElement jsonElement, JsonWriter writer) throws JsonIOException { public void toJson(JsonElement jsonElement, JsonWriter writer) throws JsonIOException {
boolean oldLenient = writer.isLenient(); boolean oldLenient = writer.isLenient();
writer.setLenient(true); writer.setLenient(lenient);
boolean oldOmitQuotes = writer.getOmitQuotes();
writer.setOmitQuotes(omitQuotes);
boolean oldHtmlSafe = writer.isHtmlSafe(); boolean oldHtmlSafe = writer.isHtmlSafe();
writer.setHtmlSafe(htmlSafe); writer.setHtmlSafe(htmlSafe);
boolean oldSerializeNulls = writer.getSerializeNulls(); boolean oldSerializeNulls = writer.getSerializeNulls();
@ -856,6 +843,7 @@ public final class Gson {
throw error; throw error;
} finally { } finally {
writer.setLenient(oldLenient); writer.setLenient(oldLenient);
writer.setOmitQuotes(oldOmitQuotes);
writer.setHtmlSafe(oldHtmlSafe); writer.setHtmlSafe(oldHtmlSafe);
writer.setSerializeNulls(oldSerializeNulls); writer.setSerializeNulls(oldSerializeNulls);
} }
@ -989,7 +977,7 @@ public final class Gson {
public <T> T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException { public <T> T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException {
boolean isEmpty = true; boolean isEmpty = true;
boolean oldLenient = reader.isLenient(); boolean oldLenient = reader.isLenient();
reader.setLenient(true); reader.setLenient(lenient);
try { try {
reader.peek(); reader.peek();
isEmpty = false; isEmpty = false;

View File

@ -35,18 +35,7 @@ import com.google.gson.internal.sql.SqlTypesSupport;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonReader;
import static com.google.gson.Gson.DEFAULT_COMPLEX_MAP_KEYS; import static com.google.gson.internal.DefaultConfig.*;
import static com.google.gson.Gson.DEFAULT_DATE_PATTERN;
import static com.google.gson.Gson.DEFAULT_DUPLICATE_MAP_KEYS;
import static com.google.gson.Gson.DEFAULT_ESCAPE_HTML;
import static com.google.gson.Gson.DEFAULT_JSON_NON_EXECUTABLE;
import static com.google.gson.Gson.DEFAULT_LENIENT;
import static com.google.gson.Gson.DEFAULT_NUMBER_TO_NUMBER_STRATEGY;
import static com.google.gson.Gson.DEFAULT_OBJECT_TO_NUMBER_STRATEGY;
import static com.google.gson.Gson.DEFAULT_PRETTY_PRINT;
import static com.google.gson.Gson.DEFAULT_SERIALIZE_NULLS;
import static com.google.gson.Gson.DEFAULT_SPECIALIZE_FLOAT_VALUES;
import static com.google.gson.Gson.DEFAULT_USE_JDK_UNSAFE;
/** /**
* <p>Use this builder to construct a {@link Gson} instance when you need to set configuration * <p>Use this builder to construct a {@link Gson} instance when you need to set configuration
@ -100,6 +89,7 @@ public final class GsonBuilder {
private boolean prettyPrinting = DEFAULT_PRETTY_PRINT; private boolean prettyPrinting = DEFAULT_PRETTY_PRINT;
private boolean generateNonExecutableJson = DEFAULT_JSON_NON_EXECUTABLE; private boolean generateNonExecutableJson = DEFAULT_JSON_NON_EXECUTABLE;
private boolean lenient = DEFAULT_LENIENT; private boolean lenient = DEFAULT_LENIENT;
private boolean omitQuotes = DEFAULT_OMIT_QUOTES;
private boolean useJdkUnsafe = DEFAULT_USE_JDK_UNSAFE; private boolean useJdkUnsafe = DEFAULT_USE_JDK_UNSAFE;
private ToNumberStrategy objectToNumberStrategy = DEFAULT_OBJECT_TO_NUMBER_STRATEGY; private ToNumberStrategy objectToNumberStrategy = DEFAULT_OBJECT_TO_NUMBER_STRATEGY;
private ToNumberStrategy numberToNumberStrategy = DEFAULT_NUMBER_TO_NUMBER_STRATEGY; private ToNumberStrategy numberToNumberStrategy = DEFAULT_NUMBER_TO_NUMBER_STRATEGY;
@ -131,6 +121,7 @@ public final class GsonBuilder {
this.escapeHtmlChars = gson.htmlSafe; this.escapeHtmlChars = gson.htmlSafe;
this.prettyPrinting = gson.prettyPrinting; this.prettyPrinting = gson.prettyPrinting;
this.lenient = gson.lenient; this.lenient = gson.lenient;
this.omitQuotes = gson.omitQuotes;
this.serializeSpecialFloatingPointValues = gson.serializeSpecialFloatingPointValues; this.serializeSpecialFloatingPointValues = gson.serializeSpecialFloatingPointValues;
this.longSerializationPolicy = gson.longSerializationPolicy; this.longSerializationPolicy = gson.longSerializationPolicy;
this.datePattern = gson.datePattern; this.datePattern = gson.datePattern;
@ -456,6 +447,15 @@ public final class GsonBuilder {
return this; return this;
} }
/**
* By default, Gson always writes quotes around entry names.
* This option allows omitting quotes if the name is alphanumeric.
*/
public GsonBuilder setOmitQuotes() {
omitQuotes = true;
return this;
}
/** /**
* By default, Gson escapes HTML characters such as &lt; &gt; etc. Use this option to configure * By default, Gson escapes HTML characters such as &lt; &gt; etc. Use this option to configure
* Gson to pass-through HTML characters as is. * Gson to pass-through HTML characters as is.
@ -694,7 +694,7 @@ public final class GsonBuilder {
return new Gson(excluder, fieldNamingPolicy, new HashMap<>(instanceCreators), return new Gson(excluder, fieldNamingPolicy, new HashMap<>(instanceCreators),
serializeNulls, complexMapKeySerialization, duplicateMapKeyDeserialization, serializeNulls, complexMapKeySerialization, duplicateMapKeyDeserialization,
generateNonExecutableJson, escapeHtmlChars, prettyPrinting, lenient, generateNonExecutableJson, escapeHtmlChars, prettyPrinting, lenient, omitQuotes,
serializeSpecialFloatingPointValues, useJdkUnsafe, longSerializationPolicy, serializeSpecialFloatingPointValues, useJdkUnsafe, longSerializationPolicy,
datePattern, dateStyle, timeStyle, new ArrayList<>(this.factories), datePattern, dateStyle, timeStyle, new ArrayList<>(this.factories),
new ArrayList<>(this.hierarchyFactories), factories, new ArrayList<>(this.hierarchyFactories), factories,

View File

@ -0,0 +1,23 @@
package com.google.gson.internal;
import com.google.gson.*;
import com.google.gson.reflect.*;
public class DefaultConfig {
public static final boolean DEFAULT_JSON_NON_EXECUTABLE = false;
public static final boolean DEFAULT_LENIENT = false;
public static final boolean DEFAULT_OMIT_QUOTES = false;
public static final boolean DEFAULT_PRETTY_PRINT = false;
public static final boolean DEFAULT_ESCAPE_HTML = true;
public static final boolean DEFAULT_SERIALIZE_NULLS = false;
public static final boolean DEFAULT_COMPLEX_MAP_KEYS = false;
public static final boolean DEFAULT_DUPLICATE_MAP_KEYS = false;
public static final boolean DEFAULT_SPECIALIZE_FLOAT_VALUES = false;
public static final boolean DEFAULT_USE_JDK_UNSAFE = true;
public static final String DEFAULT_DATE_PATTERN = null;
public static final FieldNamingStrategy DEFAULT_FIELD_NAMING_STRATEGY = FieldNamingPolicy.IDENTITY;
public static final ToNumberStrategy DEFAULT_OBJECT_TO_NUMBER_STRATEGY = ToNumberPolicy.DOUBLE;
public static final ToNumberStrategy DEFAULT_NUMBER_TO_NUMBER_STRATEGY = ToNumberPolicy.LAZILY_PARSED_NUMBER;
public static final TypeToken<?> NULL_KEY_SURROGATE = TypeToken.get(Object.class);
public static final String JSON_NON_EXECUTABLE_PREFIX = ")]}'\n";
}

View File

@ -65,6 +65,13 @@ public final class ArrayTypeAdapter<E> extends TypeAdapter<Object> {
in.nextNull(); in.nextNull();
return null; return null;
} }
Object array;
if (in.isLenient() && in.peek() != JsonToken.BEGIN_ARRAY) {
// Coerce
array = Array.newInstance(componentType, 1);
Array.set(array, 0, componentTypeAdapter.read(in));
return array;
}
List<E> list = new ArrayList<>(); List<E> list = new ArrayList<>();
in.beginArray(); in.beginArray();
@ -75,7 +82,7 @@ public final class ArrayTypeAdapter<E> extends TypeAdapter<Object> {
in.endArray(); in.endArray();
int size = list.size(); int size = list.size();
Object array = Array.newInstance(componentType, size); array = Array.newInstance(componentType, size);
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
Array.set(array, i, list.get(i)); Array.set(array, i, list.get(i));
} }

View File

@ -77,12 +77,17 @@ public final class CollectionTypeAdapterFactory implements TypeAdapterFactory {
} }
Collection<E> collection = constructor.construct(); Collection<E> collection = constructor.construct();
in.beginArray(); if (!in.isLenient() || in.peek() == JsonToken.BEGIN_ARRAY) {
while (in.hasNext()) { in.beginArray();
E instance = elementTypeAdapter.read(in); while (in.hasNext()) {
collection.add(instance); E instance = elementTypeAdapter.read(in);
collection.add(instance);
}
in.endArray();
} else {
// Coerce
collection.add(elementTypeAdapter.read(in));
} }
in.endArray();
return collection; return collection;
} }

View File

@ -16,7 +16,7 @@
package com.google.gson.stream; package com.google.gson.stream;
import com.google.gson.internal.JsonReaderInternalAccess; import com.google.gson.internal.*;
import com.google.gson.internal.bind.JsonTreeReader; import com.google.gson.internal.bind.JsonTreeReader;
import java.io.Closeable; import java.io.Closeable;
import java.io.EOFException; import java.io.EOFException;
@ -226,7 +226,7 @@ public class JsonReader implements Closeable {
private final Reader in; private final Reader in;
/** True to accept non-spec compliant JSON */ /** True to accept non-spec compliant JSON */
private boolean lenient = false; private boolean lenient = DefaultConfig.DEFAULT_LENIENT;
static final int BUFFER_SIZE = 1024; static final int BUFFER_SIZE = 1024;
/** /**
@ -315,8 +315,7 @@ public class JsonReader implements Closeable {
* <li>Names that are unquoted or {@code 'single quoted'}. * <li>Names that are unquoted or {@code 'single quoted'}.
* <li>Strings that are unquoted or {@code 'single quoted'}. * <li>Strings that are unquoted or {@code 'single quoted'}.
* <li>Array elements separated by {@code ;} instead of {@code ,}. * <li>Array elements separated by {@code ;} instead of {@code ,}.
* <li>Unnecessary array separators. These are interpreted as if null * <li>Unnecessary array separators. These are ignored.
* was the omitted value.
* <li>Names and values separated by {@code =} or {@code =>} instead of * <li>Names and values separated by {@code =} or {@code =>} instead of
* {@code :}. * {@code :}.
* <li>Name/value pairs separated by {@code ;} instead of {@code ,}. * <li>Name/value pairs separated by {@code ;} instead of {@code ,}.
@ -473,7 +472,7 @@ public class JsonReader implements Closeable {
case ',': case ',':
break; break;
default: default:
throw syntaxError("Unterminated array"); throw syntaxError("Unterminated array at " + (char)c);
} }
} else if (peekStack == JsonScope.EMPTY_OBJECT || peekStack == JsonScope.NONEMPTY_OBJECT) { } else if (peekStack == JsonScope.EMPTY_OBJECT || peekStack == JsonScope.NONEMPTY_OBJECT) {
stack[stackSize - 1] = JsonScope.DANGLING_NAME; stack[stackSize - 1] = JsonScope.DANGLING_NAME;
@ -488,7 +487,7 @@ public class JsonReader implements Closeable {
case ',': case ',':
break; break;
default: default:
throw syntaxError("Unterminated object"); throw syntaxError("Unterminated object at " + (char)c);
} }
} }
int c = nextNonWhitespace(true); int c = nextNonWhitespace(true);
@ -546,35 +545,8 @@ public class JsonReader implements Closeable {
throw new IllegalStateException("JsonReader is closed"); throw new IllegalStateException("JsonReader is closed");
} }
int c = nextNonWhitespace(true); if (checkNextNonWhitespace(peekStack))
switch (c) { return peeked;
case ']':
if (peekStack == JsonScope.EMPTY_ARRAY) {
return peeked = PEEKED_END_ARRAY;
}
// fall-through to handle ",]"
case ';':
case ',':
// In lenient mode, a 0-length literal in an array means 'null'.
if (peekStack == JsonScope.EMPTY_ARRAY || peekStack == JsonScope.NONEMPTY_ARRAY) {
checkLenient();
pos--;
return peeked = PEEKED_NULL;
} else {
throw syntaxError("Unexpected value");
}
case '\'':
checkLenient();
return peeked = PEEKED_SINGLE_QUOTED;
case '"':
return peeked = PEEKED_DOUBLE_QUOTED;
case '[':
return peeked = PEEKED_BEGIN_ARRAY;
case '{':
return peeked = PEEKED_BEGIN_OBJECT;
default:
pos--; // Don't consume the first character in a literal value.
}
int result = peekKeyword(); int result = peekKeyword();
if (result != PEEKED_NONE) { if (result != PEEKED_NONE) {
@ -594,6 +566,45 @@ public class JsonReader implements Closeable {
return peeked = PEEKED_UNQUOTED; return peeked = PEEKED_UNQUOTED;
} }
private boolean checkNextNonWhitespace(int peekStack) throws IOException {
int c = nextNonWhitespace(true);
switch (c) {
case ']':
if (peekStack == JsonScope.EMPTY_ARRAY || peekStack == JsonScope.NONEMPTY_ARRAY) {
peeked = PEEKED_END_ARRAY;
return true;
}
throw syntaxError("Unexpected value");
case ';':
case ',':
// In lenient mode, a 0-length literal in an array should be skipped.
if (peekStack == JsonScope.EMPTY_ARRAY || peekStack == JsonScope.NONEMPTY_ARRAY) {
checkLenient();
//pos--;
//peeked = PEEKED_NULL;
return checkNextNonWhitespace(peekStack);
} else {
throw syntaxError("Unexpected value");
}
case '\'':
checkLenient();
peeked = PEEKED_SINGLE_QUOTED;
return true;
case '"':
peeked = PEEKED_DOUBLE_QUOTED;
return true;
case '[':
peeked = PEEKED_BEGIN_ARRAY;
return true;
case '{':
peeked = PEEKED_BEGIN_OBJECT;
return true;
default:
pos--; // Don't consume the first character in a literal value.
}
return false;
}
private int peekKeyword() throws IOException { private int peekKeyword() throws IOException {
// Figure out which keyword we're matching against by its first character. // Figure out which keyword we're matching against by its first character.
char c = buffer[pos]; char c = buffer[pos];
@ -1198,10 +1209,14 @@ public class JsonReader implements Closeable {
} }
peeked = PEEKED_BUFFERED; peeked = PEEKED_BUFFERED;
double asDouble = Double.parseDouble(peekedString); // don't catch this NumberFormatException. if (peekedString.startsWith("0x")) {
result = (int) asDouble; result = Integer.decode(peekedString);
if (result != asDouble) { // Make sure no precision was lost casting to 'int'. } else {
throw new NumberFormatException("Expected an int but was " + peekedString + locationString()); double asDouble = Double.parseDouble(peekedString); // don't catch this NumberFormatException.
result = (int) asDouble;
if (result != asDouble) { // Make sure no precision was lost casting to 'int'.
throw new NumberFormatException("Expected an int but was " + peekedString + locationString());
}
} }
peekedString = null; peekedString = null;
peeked = PEEKED_NONE; peeked = PEEKED_NONE;
@ -1254,7 +1269,8 @@ public class JsonReader implements Closeable {
pos += peekedNumberLength; pos += peekedNumberLength;
} }
peeked = PEEKED_NONE; peeked = PEEKED_NONE;
} while (count != 0); } while (count > 0);
if (count < 0) throw new IllegalStateException("Attempt to skip led outside its parent");
pathIndices[stackSize - 1]++; pathIndices[stackSize - 1]++;
pathNames[stackSize - 1] = "null"; pathNames[stackSize - 1] = "null";
@ -1452,7 +1468,8 @@ public class JsonReader implements Closeable {
String locationString() { String locationString() {
int line = lineNumber + 1; int line = lineNumber + 1;
int column = pos - lineStart + 1; int column = pos - lineStart + 1;
return " at line " + line + " column " + column + " path " + getPath(); String charInterjection = pos < buffer.length ? " (char '" + buffer[pos] + "')" : "";
return " at line " + line + " column " + column + charInterjection + " path " + getPath();
} }
private String getPath(boolean usePreviousPath) { private String getPath(boolean usePreviousPath) {

View File

@ -16,6 +16,8 @@
package com.google.gson.stream; package com.google.gson.stream;
import com.google.gson.internal.*;
import java.io.Closeable; import java.io.Closeable;
import java.io.Flushable; import java.io.Flushable;
import java.io.IOException; import java.io.IOException;
@ -190,7 +192,9 @@ public class JsonWriter implements Closeable, Flushable {
*/ */
private String separator = ":"; private String separator = ":";
private boolean lenient; private boolean lenient = DefaultConfig.DEFAULT_LENIENT;
private boolean omitQuotes = DefaultConfig.DEFAULT_OMIT_QUOTES;
private boolean htmlSafe; private boolean htmlSafe;
@ -286,11 +290,25 @@ public class JsonWriter implements Closeable, Flushable {
return serializeNulls; return serializeNulls;
} }
/**
* Sets whether serialized entry names may omit quotes (like in json5)
* The default is false
*/
public final void setOmitQuotes(boolean omitQuotes) {
this.omitQuotes = omitQuotes;
}
public final boolean getOmitQuotes() {
return omitQuotes;
}
/** /**
* Insert a comment at the current location. * Insert a comment at the current location.
* May create a new line. * May create a new line.
* This writer MUST be lenient to use this
*/ */
public JsonWriter comment(String comment) throws IOException { public JsonWriter comment(String comment) throws IOException {
if (!lenient) throw new MalformedJsonException("Cannot write comment in non-lenient JsonWriter.");
if (comment == null || comment.isBlank()) return this; if (comment == null || comment.isBlank()) return this;
String[] parts = comment.split("\n"); String[] parts = comment.split("\n");
if (indent == null) { if (indent == null) {
@ -424,7 +442,12 @@ public class JsonWriter implements Closeable, Flushable {
private void writeDeferredName() throws IOException { private void writeDeferredName() throws IOException {
if (deferredName != null) { if (deferredName != null) {
beforeName(); beforeName();
string(deferredName); if (omitQuotes && deferredName.matches("[a-zA-Z_$][\\w$]*")) {
out.write(deferredName);
}
else {
string(deferredName);
}
deferredName = null; deferredName = null;
} }
} }

View File

@ -54,7 +54,7 @@ public final class GsonTest extends TestCase {
public void testOverridesDefaultExcluder() { public void testOverridesDefaultExcluder() {
Gson gson = new Gson(CUSTOM_EXCLUDER, CUSTOM_FIELD_NAMING_STRATEGY, Gson gson = new Gson(CUSTOM_EXCLUDER, CUSTOM_FIELD_NAMING_STRATEGY,
new HashMap<Type, InstanceCreator<?>>(), true, false, false, true, false, new HashMap<Type, InstanceCreator<?>>(), true, false, false, true, false,
true, true, false, true, LongSerializationPolicy.DEFAULT, null, DateFormat.DEFAULT, true, true, false, false, true, LongSerializationPolicy.DEFAULT, null, DateFormat.DEFAULT,
DateFormat.DEFAULT, new ArrayList<TypeAdapterFactory>(), DateFormat.DEFAULT, new ArrayList<TypeAdapterFactory>(),
new ArrayList<TypeAdapterFactory>(), new ArrayList<TypeAdapterFactory>(), new ArrayList<TypeAdapterFactory>(), new ArrayList<TypeAdapterFactory>(),
CUSTOM_OBJECT_TO_NUMBER_STRATEGY, CUSTOM_NUMBER_TO_NUMBER_STRATEGY, CUSTOM_OBJECT_TO_NUMBER_STRATEGY, CUSTOM_NUMBER_TO_NUMBER_STRATEGY,
@ -69,7 +69,7 @@ public final class GsonTest extends TestCase {
public void testClonedTypeAdapterFactoryListsAreIndependent() { public void testClonedTypeAdapterFactoryListsAreIndependent() {
Gson original = new Gson(CUSTOM_EXCLUDER, CUSTOM_FIELD_NAMING_STRATEGY, Gson original = new Gson(CUSTOM_EXCLUDER, CUSTOM_FIELD_NAMING_STRATEGY,
new HashMap<Type, InstanceCreator<?>>(), true, false, false, true, false, new HashMap<Type, InstanceCreator<?>>(), true, false, false, true, false,
true, true, false, true, LongSerializationPolicy.DEFAULT, null, DateFormat.DEFAULT, true, true, false, false, true, LongSerializationPolicy.DEFAULT, null, DateFormat.DEFAULT,
DateFormat.DEFAULT, new ArrayList<TypeAdapterFactory>(), DateFormat.DEFAULT, new ArrayList<TypeAdapterFactory>(),
new ArrayList<TypeAdapterFactory>(), new ArrayList<TypeAdapterFactory>(), new ArrayList<TypeAdapterFactory>(), new ArrayList<TypeAdapterFactory>(),
CUSTOM_OBJECT_TO_NUMBER_STRATEGY, CUSTOM_NUMBER_TO_NUMBER_STRATEGY, CUSTOM_OBJECT_TO_NUMBER_STRATEGY, CUSTOM_NUMBER_TO_NUMBER_STRATEGY,
@ -91,7 +91,7 @@ public final class GsonTest extends TestCase {
public void testNewJsonWriter_Default() throws IOException { public void testNewJsonWriter_Default() throws IOException {
StringWriter writer = new StringWriter(); StringWriter writer = new StringWriter();
JsonWriter jsonWriter = new Gson().newJsonWriter(writer); JsonWriter jsonWriter = new GsonBuilder().create().newJsonWriter(writer);
jsonWriter.beginObject(); jsonWriter.beginObject();
jsonWriter.name("test"); jsonWriter.name("test");
jsonWriter.nullValue(); jsonWriter.nullValue();
@ -137,7 +137,7 @@ public final class GsonTest extends TestCase {
public void testNewJsonReader_Default() throws IOException { public void testNewJsonReader_Default() throws IOException {
String json = "test"; // String without quotes String json = "test"; // String without quotes
JsonReader jsonReader = new Gson().newJsonReader(new StringReader(json)); JsonReader jsonReader = new GsonBuilder().create().newJsonReader(new StringReader(json));
try { try {
jsonReader.nextString(); jsonReader.nextString();
fail(); fail();

View File

@ -203,7 +203,7 @@ public final class MixedStreamTest extends TestCase {
StringWriter writer = new StringWriter(); StringWriter writer = new StringWriter();
JsonWriter jsonWriter = new JsonWriter(writer); JsonWriter jsonWriter = new JsonWriter(writer);
new GsonBuilder().serializeSpecialFloatingPointValues().create() new GsonBuilder().setLenient().serializeSpecialFloatingPointValues().create()
.toJson(doubles, type, jsonWriter); .toJson(doubles, type, jsonWriter);
assertEquals("[NaN,-Infinity,Infinity,-0.0,0.5,0.0]", writer.toString()); assertEquals("[NaN,-Infinity,Infinity,-0.0,0.5,0.0]", writer.toString());

View File

@ -33,7 +33,7 @@ public class ToNumberPolicyTest extends TestCase {
strategy.readNumber(fromString("1e400")); strategy.readNumber(fromString("1e400"));
fail(); fail();
} catch (MalformedJsonException expected) { } catch (MalformedJsonException expected) {
assertEquals("JSON forbids NaN and infinities: Infinity at line 1 column 6 path $", expected.getMessage()); assertEquals("JSON forbids NaN and infinities: Infinity at line 1 column 6 (char '\0') path $", expected.getMessage());
} }
try { try {
strategy.readNumber(fromString("\"not-a-number\"")); strategy.readNumber(fromString("\"not-a-number\""));
@ -74,19 +74,19 @@ public class ToNumberPolicyTest extends TestCase {
strategy.readNumber(fromString("NaN")); strategy.readNumber(fromString("NaN"));
fail(); fail();
} catch (MalformedJsonException expected) { } catch (MalformedJsonException expected) {
assertEquals("Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 1 path $", expected.getMessage()); assertEquals("Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 1 (char 'N') path $", expected.getMessage());
} }
try { try {
strategy.readNumber(fromString("Infinity")); strategy.readNumber(fromString("Infinity"));
fail(); fail();
} catch (MalformedJsonException expected) { } catch (MalformedJsonException expected) {
assertEquals("Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 1 path $", expected.getMessage()); assertEquals("Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 1 (char 'I') path $", expected.getMessage());
} }
try { try {
strategy.readNumber(fromString("-Infinity")); strategy.readNumber(fromString("-Infinity"));
fail(); fail();
} catch (MalformedJsonException expected) { } catch (MalformedJsonException expected) {
assertEquals("Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 1 path $", expected.getMessage()); assertEquals("Use JsonReader.setLenient(true) to accept malformed JSON at line 1 column 1 (char '-') path $", expected.getMessage());
} }
} }

View File

@ -186,7 +186,7 @@ public class ArrayTest extends TestCase {
} }
public void testArrayOfPrimitivesAsObjectsDeserialization() throws Exception { public void testArrayOfPrimitivesAsObjectsDeserialization() throws Exception {
String json = "[1,'abc',0.3,1.1,5]"; String json = "[1,\"abc\",0.3,1.1,5]";
Object[] objs = gson.fromJson(json, Object[].class); Object[] objs = gson.fromJson(json, Object[].class);
assertEquals(1, ((Number)objs[0]).intValue()); assertEquals(1, ((Number)objs[0]).intValue());
assertEquals("abc", objs[1]); assertEquals("abc", objs[1]);
@ -249,8 +249,8 @@ public class ArrayTest extends TestCase {
* Regression tests for Issue 272 * Regression tests for Issue 272
*/ */
public void testMultidimenstionalArraysDeserialization() { public void testMultidimenstionalArraysDeserialization() {
String json = "[['3m Co','71.72','0.02','0.03','4/2 12:00am','Manufacturing']," String json = "[[\"3m Co\",\"71.72\",\"0.02\",\"0.03\",\"4/2 12:00am\",\"Manufacturing\"],"
+ "['Alcoa Inc','29.01','0.42','1.47','4/1 12:00am','Manufacturing']]"; + "[\"Alcoa Inc\",\"29.01\",\"0.42\",\"1.47\",\"4/1 12:00am\",\"Manufacturing\"]]";
String[][] items = gson.fromJson(json, String[][].class); String[][] items = gson.fromJson(json, String[][].class);
assertEquals("3m Co", items[0][0]); assertEquals("3m Co", items[0][0]);
assertEquals("Manufacturing", items[1][5]); assertEquals("Manufacturing", items[1][5]);

View File

@ -101,7 +101,7 @@ public class CollectionTest extends TestCase {
} }
public void testLinkedListDeserialization() { public void testLinkedListDeserialization() {
String json = "['a1','a2']"; String json = "[\"a1\",\"a2\"]";
Type linkedListType = new TypeToken<LinkedList<String>>() {}.getType(); Type linkedListType = new TypeToken<LinkedList<String>>() {}.getType();
List<String> list = gson.fromJson(json, linkedListType); List<String> list = gson.fromJson(json, linkedListType);
assertEquals("a1", list.get(0)); assertEquals("a1", list.get(0));
@ -119,7 +119,7 @@ public class CollectionTest extends TestCase {
} }
public void testQueueDeserialization() { public void testQueueDeserialization() {
String json = "['a1','a2']"; String json = "[\"a1\",\"a2\"]";
Type queueType = new TypeToken<Queue<String>>() {}.getType(); Type queueType = new TypeToken<Queue<String>>() {}.getType();
Queue<String> queue = gson.fromJson(json, queueType); Queue<String> queue = gson.fromJson(json, queueType);
assertEquals("a1", queue.element()); assertEquals("a1", queue.element());
@ -385,7 +385,7 @@ public class CollectionTest extends TestCase {
assertTrue(json.contains("2")); assertTrue(json.contains("2"));
} }
public void testSetDeserialization() { public void testSetDeserialization() {
String json = "[{value:1},{value:2}]"; String json = "[{\"value\":1},{\"value\":2}]";
Type type = new TypeToken<Set<Entry>>() {}.getType(); Type type = new TypeToken<Set<Entry>>() {}.getType();
Set<Entry> set = gson.fromJson(json, type); Set<Entry> set = gson.fromJson(json, type);
assertEquals(2, set.size()); assertEquals(2, set.size());

View File

@ -56,7 +56,7 @@ public class ConcurrencyTest extends TestCase {
*/ */
public void testSingleThreadDeserialization() { public void testSingleThreadDeserialization() {
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
gson.fromJson("{'a':'hello','b':'world','i':1}", MyObject.class); gson.fromJson("{\"a\":\"hello\",\"b\":\"world\",\"i\":1}", MyObject.class);
} }
} }
@ -106,7 +106,7 @@ public class ConcurrencyTest extends TestCase {
try { try {
startLatch.await(); startLatch.await();
for (int i = 0; i < 10; i++) { for (int i = 0; i < 10; i++) {
gson.fromJson("{'a':'hello','b':'world','i':1}", MyObject.class); gson.fromJson("{\"a\":\"hello\",\"b\":\"world\",\"i\":1}", MyObject.class);
} }
} catch (Throwable t) { } catch (Throwable t) {
failed.set(true); failed.set(true);

View File

@ -112,12 +112,11 @@ public class CustomDeserializerTest extends TestCase {
public void testJsonTypeFieldBasedDeserialization() { public void testJsonTypeFieldBasedDeserialization() {
String json = "{field1:'abc',field2:'def',__type__:'SUB_TYPE1'}"; String json = "{field1:'abc',field2:'def',__type__:'SUB_TYPE1'}";
Gson gson = new GsonBuilder().registerTypeAdapter(MyBase.class, new JsonDeserializer<MyBase>() { Gson gson = new GsonBuilder()
@Override public MyBase deserialize(JsonElement json, Type pojoType, .setLenient()
JsonDeserializationContext context) throws JsonParseException { .registerTypeAdapter(MyBase.class, (JsonDeserializer<MyBase>) (json1, pojoType, context) -> {
String type = json.getAsJsonObject().get(MyBase.TYPE_ACCESS).getAsString(); String type = json1.getAsJsonObject().get(MyBase.TYPE_ACCESS).getAsString();
return context.deserialize(json, SubTypes.valueOf(type).getSubclass()); return context.deserialize(json1, SubTypes.valueOf(type).getSubclass());
}
}).create(); }).create();
SubType1 target = (SubType1) gson.fromJson(json, MyBase.class); SubType1 target = (SubType1) gson.fromJson(json, MyBase.class);
assertEquals("abc", target.field1); assertEquals("abc", target.field1);
@ -150,13 +149,8 @@ public class CustomDeserializerTest extends TestCase {
public void testCustomDeserializerReturnsNullForTopLevelObject() { public void testCustomDeserializerReturnsNullForTopLevelObject() {
Gson gson = new GsonBuilder() Gson gson = new GsonBuilder()
.registerTypeAdapter(Base.class, new JsonDeserializer<Base>() { .setLenient()
@Override .registerTypeAdapter(Base.class, (JsonDeserializer<Base>) (json, typeOfT, context) -> null).create();
public Base deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
return null;
}
}).create();
String json = "{baseName:'Base',subName:'SubRevised'}"; String json = "{baseName:'Base',subName:'SubRevised'}";
Base target = gson.fromJson(json, Base.class); Base target = gson.fromJson(json, Base.class);
assertNull(target); assertNull(target);
@ -164,13 +158,8 @@ public class CustomDeserializerTest extends TestCase {
public void testCustomDeserializerReturnsNull() { public void testCustomDeserializerReturnsNull() {
Gson gson = new GsonBuilder() Gson gson = new GsonBuilder()
.registerTypeAdapter(Base.class, new JsonDeserializer<Base>() { .setLenient()
@Override .registerTypeAdapter(Base.class, (JsonDeserializer<Base>) (json, typeOfT, context) -> null).create();
public Base deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
return null;
}
}).create();
String json = "{base:{baseName:'Base',subName:'SubRevised'}}"; String json = "{base:{baseName:'Base',subName:'SubRevised'}}";
ClassWithBaseField target = gson.fromJson(json, ClassWithBaseField.class); ClassWithBaseField target = gson.fromJson(json, ClassWithBaseField.class);
assertNull(target.base); assertNull(target.base);
@ -178,13 +167,8 @@ public class CustomDeserializerTest extends TestCase {
public void testCustomDeserializerReturnsNullForArrayElements() { public void testCustomDeserializerReturnsNullForArrayElements() {
Gson gson = new GsonBuilder() Gson gson = new GsonBuilder()
.registerTypeAdapter(Base.class, new JsonDeserializer<Base>() { .setLenient()
@Override .registerTypeAdapter(Base.class, (JsonDeserializer<Base>) (json, typeOfT, context) -> null).create();
public Base deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
return null;
}
}).create();
String json = "[{baseName:'Base'},{baseName:'Base'}]"; String json = "[{baseName:'Base'},{baseName:'Base'}]";
Base[] target = gson.fromJson(json, Base[].class); Base[] target = gson.fromJson(json, Base[].class);
assertNull(target[0]); assertNull(target[0]);
@ -193,13 +177,8 @@ public class CustomDeserializerTest extends TestCase {
public void testCustomDeserializerReturnsNullForArrayElementsForArrayField() { public void testCustomDeserializerReturnsNullForArrayElementsForArrayField() {
Gson gson = new GsonBuilder() Gson gson = new GsonBuilder()
.registerTypeAdapter(Base.class, new JsonDeserializer<Base>() { .setLenient()
@Override .registerTypeAdapter(Base.class, (JsonDeserializer<Base>) (json, typeOfT, context) -> null).create();
public Base deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
throws JsonParseException {
return null;
}
}).create();
String json = "{bases:[{baseName:'Base'},{baseName:'Base'}]}"; String json = "{bases:[{baseName:'Base'},{baseName:'Base'}]}";
ClassWithBaseArray target = gson.fromJson(json, ClassWithBaseArray.class); ClassWithBaseArray target = gson.fromJson(json, ClassWithBaseArray.class);
assertNull(target.bases[0]); assertNull(target.bases[0]);

View File

@ -264,7 +264,7 @@ public class CustomTypeAdaptersTest extends TestCase {
} }
}); });
Gson gson = gsonBuilder.create(); Gson gson = gsonBuilder.create();
String json = "'0123456789'"; String json = "\"0123456789\"";
byte[] actual = gson.fromJson(json, byte[].class); byte[] actual = gson.fromJson(json, byte[].class);
byte[] expected = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; byte[] expected = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
for (int i = 0; i < actual.length; ++i) { for (int i = 0; i < actual.length; ++i) {
@ -338,7 +338,7 @@ public class CustomTypeAdaptersTest extends TestCase {
.registerTypeAdapter(StringHolder.class, new StringHolderTypeAdapter()) .registerTypeAdapter(StringHolder.class, new StringHolderTypeAdapter())
.create(); .create();
Type setType = new TypeToken<Set<StringHolder>>() {}.getType(); Type setType = new TypeToken<Set<StringHolder>>() {}.getType();
Set<StringHolder> setOfHolders = gson.fromJson("['Jacob:Tomaw']", setType); Set<StringHolder> setOfHolders = gson.fromJson("[\"Jacob:Tomaw\"]", setType);
assertEquals(1, setOfHolders.size()); assertEquals(1, setOfHolders.size());
StringHolder foo = setOfHolders.iterator().next(); StringHolder foo = setOfHolders.iterator().next();
assertEquals("Jacob", foo.part1); assertEquals("Jacob", foo.part1);
@ -376,7 +376,7 @@ public class CustomTypeAdaptersTest extends TestCase {
.registerTypeAdapter(StringHolder.class, new StringHolderTypeAdapter()) .registerTypeAdapter(StringHolder.class, new StringHolderTypeAdapter())
.create(); .create();
Type mapType = new TypeToken<Map<String, StringHolder>>() {}.getType(); Type mapType = new TypeToken<Map<String, StringHolder>>() {}.getType();
Map<String, StringHolder> mapOfFoo = gson.fromJson("{'foo':'Jacob:Tomaw'}", mapType); Map<String, StringHolder> mapOfFoo = gson.fromJson("{\"foo\":\"Jacob:Tomaw\"}", mapType);
assertEquals(1, mapOfFoo.size()); assertEquals(1, mapOfFoo.size());
StringHolder foo = mapOfFoo.get("foo"); StringHolder foo = mapOfFoo.get("foo");
assertEquals("Jacob", foo.part1); assertEquals("Jacob", foo.part1);
@ -394,8 +394,9 @@ public class CustomTypeAdaptersTest extends TestCase {
public void testEnsureCustomDeserializerNotInvokedForNullValues() { public void testEnsureCustomDeserializerNotInvokedForNullValues() {
Gson gson = new GsonBuilder() Gson gson = new GsonBuilder()
.registerTypeAdapter(DataHolder.class, new DataHolderDeserializer()) .setLenient()
.create(); .registerTypeAdapter(DataHolder.class, new DataHolderDeserializer())
.create();
String json = "{wrappedData:null}"; String json = "{wrappedData:null}";
DataHolderWrapper actual = gson.fromJson(json, DataHolderWrapper.class); DataHolderWrapper actual = gson.fromJson(json, DataHolderWrapper.class);
assertNull(actual.wrappedData); assertNull(actual.wrappedData);
@ -404,8 +405,8 @@ public class CustomTypeAdaptersTest extends TestCase {
// Test created from Issue 352 // Test created from Issue 352
public void testRegisterHierarchyAdapterForDate() { public void testRegisterHierarchyAdapterForDate() {
Gson gson = new GsonBuilder() Gson gson = new GsonBuilder()
.registerTypeHierarchyAdapter(Date.class, new DateTypeAdapter()) .registerTypeHierarchyAdapter(Date.class, new DateTypeAdapter())
.create(); .create();
assertEquals("0", gson.toJson(new Date(0))); assertEquals("0", gson.toJson(new Date(0)));
assertEquals("0", gson.toJson(new java.sql.Date(0))); assertEquals("0", gson.toJson(new java.sql.Date(0)));
assertEquals(new Date(0), gson.fromJson("0", Date.class)); assertEquals(new Date(0), gson.fromJson("0", Date.class));

View File

@ -104,7 +104,7 @@ public class DefaultTypeAdaptersTest extends TestCase {
} catch (UnsupportedOperationException expected) { } catch (UnsupportedOperationException expected) {
} }
// Override with a custom type adapter for class. // Override with a custom type adapter for class.
gson = new GsonBuilder().registerTypeAdapter(Class.class, new MyClassTypeAdapter()).create(); gson = new GsonBuilder().setLenient().registerTypeAdapter(Class.class, new MyClassTypeAdapter()).create();
assertEquals(String.class, gson.fromJson("java.lang.String", Class.class)); assertEquals(String.class, gson.fromJson("java.lang.String", Class.class));
} }
@ -410,7 +410,7 @@ public class DefaultTypeAdaptersTest extends TestCase {
} }
public void testDefaultCalendarDeserialization() throws Exception { public void testDefaultCalendarDeserialization() throws Exception {
Gson gson = new GsonBuilder().create(); Gson gson = new Gson();
String json = "{year:2009,month:2,dayOfMonth:11,hourOfDay:14,minute:29,second:23}"; String json = "{year:2009,month:2,dayOfMonth:11,hourOfDay:14,minute:29,second:23}";
Calendar cal = gson.fromJson(json, Calendar.class); Calendar cal = gson.fromJson(json, Calendar.class);
assertEquals(2009, cal.get(Calendar.YEAR)); assertEquals(2009, cal.get(Calendar.YEAR));
@ -434,7 +434,7 @@ public class DefaultTypeAdaptersTest extends TestCase {
} }
public void testDefaultGregorianCalendarDeserialization() throws Exception { public void testDefaultGregorianCalendarDeserialization() throws Exception {
Gson gson = new GsonBuilder().create(); Gson gson = new Gson();
String json = "{year:2009,month:2,dayOfMonth:11,hourOfDay:14,minute:29,second:23}"; String json = "{year:2009,month:2,dayOfMonth:11,hourOfDay:14,minute:29,second:23}";
GregorianCalendar cal = gson.fromJson(json, GregorianCalendar.class); GregorianCalendar cal = gson.fromJson(json, GregorianCalendar.class);
assertEquals(2009, cal.get(Calendar.YEAR)); assertEquals(2009, cal.get(Calendar.YEAR));

View File

@ -1,58 +0,0 @@
/*
* Copyright (C) 2008 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.functional;
import com.google.gson.Gson;
import com.google.gson.annotations.SerializedName;
import junit.framework.TestCase;
/**
* Functional tests for enums with Proguard.
*
* @author Young Cha
*/
public class EnumWithObfuscatedTest extends TestCase {
private Gson gson;
@Override
protected void setUp() throws Exception {
super.setUp();
gson = new Gson();
}
public enum Gender {
@SerializedName("MAIL")
MALE,
@SerializedName("FEMAIL")
FEMALE
}
public void testEnumClassWithObfuscated() {
for (Gender enumConstant: Gender.class.getEnumConstants()) {
try {
Gender.class.getField(enumConstant.name());
fail("Enum is not obfuscated");
} catch (NoSuchFieldException ignore) {
}
}
assertEquals(Gender.MALE, gson.fromJson("\"MAIL\"", Gender.class));
assertEquals("\"MAIL\"", gson.toJson(Gender.MALE, Gender.class));
}
}

View File

@ -38,6 +38,7 @@ public class ExposeFieldsTest extends TestCase {
protected void setUp() throws Exception { protected void setUp() throws Exception {
super.setUp(); super.setUp();
gson = new GsonBuilder() gson = new GsonBuilder()
.setLenient()
.excludeFieldsWithoutExposeAnnotation() .excludeFieldsWithoutExposeAnnotation()
.registerTypeAdapter(SomeInterface.class, new SomeInterfaceInstanceCreator()) .registerTypeAdapter(SomeInterface.class, new SomeInterfaceInstanceCreator())
.create(); .create();

View File

@ -42,12 +42,9 @@ public class InstanceCreatorTest extends TestCase {
public void testInstanceCreatorReturnsBaseType() { public void testInstanceCreatorReturnsBaseType() {
Gson gson = new GsonBuilder() Gson gson = new GsonBuilder()
.registerTypeAdapter(Base.class, new InstanceCreator<Base>() { .setLenient()
@Override public Base createInstance(Type type) { .registerTypeAdapter(Base.class, (InstanceCreator<Base>) type -> new Base())
return new Base(); .create();
}
})
.create();
String json = "{baseName:'BaseRevised',subName:'Sub'}"; String json = "{baseName:'BaseRevised',subName:'Sub'}";
Base base = gson.fromJson(json, Base.class); Base base = gson.fromJson(json, Base.class);
assertEquals("BaseRevised", base.baseName); assertEquals("BaseRevised", base.baseName);
@ -55,12 +52,9 @@ public class InstanceCreatorTest extends TestCase {
public void testInstanceCreatorReturnsSubTypeForTopLevelObject() { public void testInstanceCreatorReturnsSubTypeForTopLevelObject() {
Gson gson = new GsonBuilder() Gson gson = new GsonBuilder()
.registerTypeAdapter(Base.class, new InstanceCreator<Base>() { .setLenient()
@Override public Base createInstance(Type type) { .registerTypeAdapter(Base.class, (InstanceCreator<Base>) type -> new Sub())
return new Sub(); .create();
}
})
.create();
String json = "{baseName:'Base',subName:'SubRevised'}"; String json = "{baseName:'Base',subName:'SubRevised'}";
Base base = gson.fromJson(json, Base.class); Base base = gson.fromJson(json, Base.class);
@ -73,12 +67,9 @@ public class InstanceCreatorTest extends TestCase {
public void testInstanceCreatorReturnsSubTypeForField() { public void testInstanceCreatorReturnsSubTypeForField() {
Gson gson = new GsonBuilder() Gson gson = new GsonBuilder()
.registerTypeAdapter(Base.class, new InstanceCreator<Base>() { .setLenient()
@Override public Base createInstance(Type type) { .registerTypeAdapter(Base.class, (InstanceCreator<Base>) type -> new Sub())
return new Sub(); .create();
}
})
.create();
String json = "{base:{baseName:'Base',subName:'SubRevised'}}"; String json = "{base:{baseName:'Base',subName:'SubRevised'}}";
ClassWithBaseField target = gson.fromJson(json, ClassWithBaseField.class); ClassWithBaseField target = gson.fromJson(json, ClassWithBaseField.class);
assertTrue(target.base instanceof Sub); assertTrue(target.base instanceof Sub);

View File

@ -65,7 +65,7 @@ public class InternationalizationTest extends TestCase {
} }
public void testStringsWithUnicodeChineseCharactersEscapedDeserialization() throws Exception { public void testStringsWithUnicodeChineseCharactersEscapedDeserialization() throws Exception {
String actual = gson.fromJson("'\\u597d\\u597d\\u597d'", String.class); String actual = gson.fromJson("\"\\u597d\\u597d\\u597d\"", String.class);
assertEquals("\u597d\u597d\u597d", actual); assertEquals("\u597d\u597d\u597d", actual);
} }
} }

View File

@ -65,7 +65,7 @@ public class JavaUtilConcurrentAtomicTest extends TestCase {
Gson gson = new GsonBuilder() Gson gson = new GsonBuilder()
.setLongSerializationPolicy(LongSerializationPolicy.STRING) .setLongSerializationPolicy(LongSerializationPolicy.STRING)
.create(); .create();
AtomicLongHolder target = gson.fromJson("{'value':'10'}", AtomicLongHolder.class); AtomicLongHolder target = gson.fromJson("{\"value\":\"10\"}", AtomicLongHolder.class);
assertEquals(10, target.value.get()); assertEquals(10, target.value.get());
String json = gson.toJson(target); String json = gson.toJson(target);
assertEquals("{\"value\":\"10\"}", json); assertEquals("{\"value\":\"10\"}", json);
@ -95,7 +95,7 @@ public class JavaUtilConcurrentAtomicTest extends TestCase {
Gson gson = new GsonBuilder() Gson gson = new GsonBuilder()
.setLongSerializationPolicy(LongSerializationPolicy.STRING) .setLongSerializationPolicy(LongSerializationPolicy.STRING)
.create(); .create();
AtomicLongArray target = gson.fromJson("['10', '13', '14']", AtomicLongArray.class); AtomicLongArray target = gson.fromJson("[\"10\", \"13\", \"14\"]", AtomicLongArray.class);
assertEquals(3, target.length()); assertEquals(3, target.length());
assertEquals(10, target.get(0)); assertEquals(10, target.get(0));
assertEquals(13, target.get(1)); assertEquals(13, target.get(1));

View File

@ -36,7 +36,7 @@ public class JavaUtilTest extends TestCase {
} }
public void testCurrency() throws Exception { public void testCurrency() throws Exception {
CurrencyHolder target = gson.fromJson("{'value':'USD'}", CurrencyHolder.class); CurrencyHolder target = gson.fromJson("{\"value\":\"USD\"}", CurrencyHolder.class);
assertEquals("USD", target.value.getCurrencyCode()); assertEquals("USD", target.value.getCurrencyCode());
String json = gson.toJson(target); String json = gson.toJson(target);
assertEquals("{\"value\":\"USD\"}", json); assertEquals("{\"value\":\"USD\"}", json);
@ -52,7 +52,7 @@ public class JavaUtilTest extends TestCase {
} }
public void testProperties() { public void testProperties() {
Properties props = gson.fromJson("{'a':'v1','b':'v2'}", Properties.class); Properties props = gson.fromJson("{\"a\":\"v1\",\"b\":\"v2\"}", Properties.class);
assertEquals("v1", props.getProperty("a")); assertEquals("v1", props.getProperty("a"));
assertEquals("v2", props.getProperty("b")); assertEquals("v2", props.getProperty("b"));
String json = gson.toJson(props); String json = gson.toJson(props);

View File

@ -49,7 +49,7 @@ public final class JsonAdapterAnnotationOnClassesTest extends TestCase {
// Also invoke the JsonAdapter javadoc sample // Also invoke the JsonAdapter javadoc sample
json = gson.toJson(new User("Inderjeet", "Singh")); json = gson.toJson(new User("Inderjeet", "Singh"));
assertEquals("{\"name\":\"Inderjeet Singh\"}", json); assertEquals("{\"name\":\"Inderjeet Singh\"}", json);
User user = gson.fromJson("{'name':'Joel Leitch'}", User.class); User user = gson.fromJson("{\"name\":\"Joel Leitch\"}", User.class);
assertEquals("Joel", user.firstName); assertEquals("Joel", user.firstName);
assertEquals("Leitch", user.lastName); assertEquals("Leitch", user.lastName);
@ -94,6 +94,7 @@ public final class JsonAdapterAnnotationOnClassesTest extends TestCase {
} }
}; };
Gson gson = new GsonBuilder() Gson gson = new GsonBuilder()
.setLenient()
.registerTypeAdapter(A.class, serializer) .registerTypeAdapter(A.class, serializer)
.create(); .create();
String json = gson.toJson(new A("abcd")); String json = gson.toJson(new A("abcd"));
@ -113,6 +114,7 @@ public final class JsonAdapterAnnotationOnClassesTest extends TestCase {
} }
}; };
Gson gson = new GsonBuilder() Gson gson = new GsonBuilder()
.setLenient()
.registerTypeAdapter(A.class, deserializer) .registerTypeAdapter(A.class, deserializer)
.create(); .create();
String json = gson.toJson(new A("abcd")); String json = gson.toJson(new A("abcd"));

View File

@ -57,12 +57,13 @@ public final class JsonAdapterAnnotationOnFieldsTest extends TestCase {
.create(); .create();
String json = gson.toJson(new Computer(new User("Inderjeet Singh"))); String json = gson.toJson(new Computer(new User("Inderjeet Singh")));
assertEquals("{\"user\":\"RegisteredUserAdapter\"}", json); assertEquals("{\"user\":\"RegisteredUserAdapter\"}", json);
Computer computer = gson.fromJson("{'user':'Inderjeet Singh'}", Computer.class); Computer computer = gson.fromJson("{\"user\":\"Inderjeet Singh\"}", Computer.class);
assertEquals("RegisteredUserAdapter", computer.user.name); assertEquals("RegisteredUserAdapter", computer.user.name);
} }
public void testFieldAnnotationTakesPrecedenceOverRegisteredTypeAdapter() { public void testFieldAnnotationTakesPrecedenceOverRegisteredTypeAdapter() {
Gson gson = new GsonBuilder() Gson gson = new GsonBuilder()
.setLenient()
.registerTypeAdapter(Part.class, new TypeAdapter<Part>() { .registerTypeAdapter(Part.class, new TypeAdapter<Part>() {
@Override public void write(JsonWriter out, Part part) throws IOException { @Override public void write(JsonWriter out, Part part) throws IOException {
throw new AssertionError(); throw new AssertionError();

View File

@ -16,13 +16,7 @@
package com.google.gson.functional; package com.google.gson.functional;
import com.google.gson.Gson; import com.google.gson.*;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSyntaxException;
import com.google.gson.common.TestTypes.BagOfPrimitives; import com.google.gson.common.TestTypes.BagOfPrimitives;
import com.google.gson.common.TestTypes.Nested; import com.google.gson.common.TestTypes.Nested;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
@ -123,9 +117,9 @@ public class JsonParserTest extends TestCase {
public void testExtraCommasInArrays() { public void testExtraCommasInArrays() {
Type type = new TypeToken<List<String>>() {}.getType(); Type type = new TypeToken<List<String>>() {}.getType();
assertEquals(Arrays.asList("a", null, "b", null, null), gson.fromJson("[a,,b,,]", type)); assertEquals(Arrays.asList("a", "b"), gson.fromJson("[a,,b,,]", type));
assertEquals(Arrays.asList(null, null), gson.fromJson("[,]", type)); assertEquals(Arrays.asList(), gson.fromJson("[,]", type));
assertEquals(Arrays.asList("a", null), gson.fromJson("[a,]", type)); assertEquals(Arrays.asList("a"), gson.fromJson("[a,]", type));
} }
public void testExtraCommasInMaps() { public void testExtraCommasInMaps() {

View File

@ -33,7 +33,7 @@ public class LeniencyTest extends TestCase {
@Override @Override
protected void setUp() throws Exception { protected void setUp() throws Exception {
super.setUp(); super.setUp();
gson = new GsonBuilder().setLenient().create(); gson = new Gson();
} }
public void testLenientFromJson() { public void testLenientFromJson() {

View File

@ -106,7 +106,7 @@ public class MapAsArrayTypeAdapterTest extends TestCase {
} }
public void testMapWithTypeVariableDeserialization() { public void testMapWithTypeVariableDeserialization() {
Gson gson = new GsonBuilder().enableComplexMapKeySerialization().create(); Gson gson = new GsonBuilder().setLenient().enableComplexMapKeySerialization().create();
String json = "{map:[[{x:2,y:3},{x:4,y:5}]]}"; String json = "{map:[[{x:2,y:3},{x:4,y:5}]]}";
Type type = new TypeToken<PointWithProperty<Point>>(){}.getType(); Type type = new TypeToken<PointWithProperty<Point>>(){}.getType();
PointWithProperty<Point> map = gson.fromJson(json, type); PointWithProperty<Point> map = gson.fromJson(json, type);

View File

@ -155,7 +155,7 @@ public class MapTest extends TestCase {
assertEquals(123, map.get("null").intValue()); assertEquals(123, map.get("null").intValue());
assertNull(map.get(null)); assertNull(map.get(null));
map = gson.fromJson("{null:123}", typeOfMap); map = gson.fromJson("{'null':123}", typeOfMap);
assertEquals(1, map.size()); assertEquals(1, map.size());
assertEquals(123, map.get("null").intValue()); assertEquals(123, map.get("null").intValue());
assertNull(map.get(null)); assertNull(map.get(null));

View File

@ -99,7 +99,7 @@ public class NullObjectAndFieldTest extends TestCase {
*/ */
public void testNullWrappedPrimitiveMemberDeserialization() { public void testNullWrappedPrimitiveMemberDeserialization() {
Gson gson = gsonBuilder.create(); Gson gson = gsonBuilder.create();
String json = "{'value':null}"; String json = "{\"value\":null}";
ClassWithNullWrappedPrimitive target = gson.fromJson(json, ClassWithNullWrappedPrimitive.class); ClassWithNullWrappedPrimitive target = gson.fromJson(json, ClassWithNullWrappedPrimitive.class);
assertNull(target.value); assertNull(target.value);
} }
@ -223,12 +223,8 @@ public class NullObjectAndFieldTest extends TestCase {
public void testCustomTypeAdapterPassesNullDesrialization() { public void testCustomTypeAdapterPassesNullDesrialization() {
Gson gson = new GsonBuilder() Gson gson = new GsonBuilder()
.registerTypeAdapter(ObjectWithField.class, new JsonDeserializer<ObjectWithField>() { .setLenient()
@Override public ObjectWithField deserialize(JsonElement json, Type type, .registerTypeAdapter(ObjectWithField.class, (JsonDeserializer<ObjectWithField>) (json, type, context) -> context.deserialize(null, type)).create();
JsonDeserializationContext context) {
return context.deserialize(null, type);
}
}).create();
String json = "{value:'value1'}"; String json = "{value:'value1'}";
ObjectWithField target = gson.fromJson(json, ObjectWithField.class); ObjectWithField target = gson.fromJson(json, ObjectWithField.class);
assertNull(target); assertNull(target);

View File

@ -346,7 +346,7 @@ public class ObjectTest extends TestCase {
return p.new Child(); return p.new Child();
} }
}).create(); }).create();
String json = "{'value2':3}"; String json = "{\"value2\":3}";
Parent.Child c = gson.fromJson(json, Parent.Child.class); Parent.Child c = gson.fromJson(json, Parent.Child.class);
assertEquals(3, c.value2); assertEquals(3, c.value2);
} }

View File

@ -16,10 +16,9 @@
package com.google.gson.functional; package com.google.gson.functional;
import com.google.gson.*;
import junit.framework.TestCase; import junit.framework.TestCase;
import com.google.gson.Gson;
/** /**
* Functional tests for Java Character values. * Functional tests for Java Character values.
* *

View File

@ -18,11 +18,7 @@ package com.google.gson.functional;
import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertArrayEquals;
import com.google.gson.Gson; import com.google.gson.*;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSyntaxException;
import com.google.gson.LongSerializationPolicy;
import com.google.gson.internal.LazilyParsedNumber; import com.google.gson.internal.LazilyParsedNumber;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
import java.io.Serializable; import java.io.Serializable;
@ -95,7 +91,7 @@ public class PrimitiveTest extends TestCase {
gson.fromJson("2147483648", byte.class); gson.fromJson("2147483648", byte.class);
fail(); fail();
} catch (JsonSyntaxException e) { } catch (JsonSyntaxException e) {
assertEquals("java.lang.NumberFormatException: Expected an int but was 2147483648 at line 1 column 11 path $", e.getMessage()); assertEquals("java.lang.NumberFormatException: Expected an int but was 2147483648 at line 1 column 11 (char '\0') path $", e.getMessage());
} }
} }
@ -133,7 +129,7 @@ public class PrimitiveTest extends TestCase {
gson.fromJson("2147483648", short.class); gson.fromJson("2147483648", short.class);
fail(); fail();
} catch (JsonSyntaxException e) { } catch (JsonSyntaxException e) {
assertEquals("java.lang.NumberFormatException: Expected an int but was 2147483648 at line 1 column 11 path $", e.getMessage()); assertEquals("java.lang.NumberFormatException: Expected an int but was 2147483648 at line 1 column 11 (char '\0') path $", e.getMessage());
} }
} }
@ -435,7 +431,7 @@ public class PrimitiveTest extends TestCase {
} }
public void testDoubleNaNSerialization() { public void testDoubleNaNSerialization() {
Gson gson = new GsonBuilder().serializeSpecialFloatingPointValues().create(); Gson gson = new GsonBuilder().setLenient().serializeSpecialFloatingPointValues().create();
double nan = Double.NaN; double nan = Double.NaN;
assertEquals("NaN", gson.toJson(nan)); assertEquals("NaN", gson.toJson(nan));
assertEquals("NaN", gson.toJson(Double.NaN)); assertEquals("NaN", gson.toJson(Double.NaN));
@ -461,7 +457,7 @@ public class PrimitiveTest extends TestCase {
} }
public void testFloatNaNSerialization() { public void testFloatNaNSerialization() {
Gson gson = new GsonBuilder().serializeSpecialFloatingPointValues().create(); Gson gson = new GsonBuilder().setLenient().serializeSpecialFloatingPointValues().create();
float nan = Float.NaN; float nan = Float.NaN;
assertEquals("NaN", gson.toJson(nan)); assertEquals("NaN", gson.toJson(nan));
assertEquals("NaN", gson.toJson(Float.NaN)); assertEquals("NaN", gson.toJson(Float.NaN));
@ -495,7 +491,7 @@ public class PrimitiveTest extends TestCase {
} }
public void testDoubleInfinitySerialization() { public void testDoubleInfinitySerialization() {
Gson gson = new GsonBuilder().serializeSpecialFloatingPointValues().create(); Gson gson = new GsonBuilder().setLenient().serializeSpecialFloatingPointValues().create();
double infinity = Double.POSITIVE_INFINITY; double infinity = Double.POSITIVE_INFINITY;
assertEquals("Infinity", gson.toJson(infinity)); assertEquals("Infinity", gson.toJson(infinity));
assertEquals("Infinity", gson.toJson(Double.POSITIVE_INFINITY)); assertEquals("Infinity", gson.toJson(Double.POSITIVE_INFINITY));
@ -521,7 +517,7 @@ public class PrimitiveTest extends TestCase {
} }
public void testFloatInfinitySerialization() { public void testFloatInfinitySerialization() {
Gson gson = new GsonBuilder().serializeSpecialFloatingPointValues().create(); Gson gson = new GsonBuilder().setLenient().serializeSpecialFloatingPointValues().create();
float infinity = Float.POSITIVE_INFINITY; float infinity = Float.POSITIVE_INFINITY;
assertEquals("Infinity", gson.toJson(infinity)); assertEquals("Infinity", gson.toJson(infinity));
assertEquals("Infinity", gson.toJson(Float.POSITIVE_INFINITY)); assertEquals("Infinity", gson.toJson(Float.POSITIVE_INFINITY));
@ -555,7 +551,7 @@ public class PrimitiveTest extends TestCase {
} }
public void testNegativeInfinitySerialization() { public void testNegativeInfinitySerialization() {
Gson gson = new GsonBuilder().serializeSpecialFloatingPointValues().create(); Gson gson = new GsonBuilder().setLenient().serializeSpecialFloatingPointValues().create();
double negativeInfinity = Double.NEGATIVE_INFINITY; double negativeInfinity = Double.NEGATIVE_INFINITY;
assertEquals("-Infinity", gson.toJson(negativeInfinity)); assertEquals("-Infinity", gson.toJson(negativeInfinity));
assertEquals("-Infinity", gson.toJson(Double.NEGATIVE_INFINITY)); assertEquals("-Infinity", gson.toJson(Double.NEGATIVE_INFINITY));
@ -581,7 +577,7 @@ public class PrimitiveTest extends TestCase {
} }
public void testNegativeInfinityFloatSerialization() { public void testNegativeInfinityFloatSerialization() {
Gson gson = new GsonBuilder().serializeSpecialFloatingPointValues().create(); Gson gson = new GsonBuilder().setLenient().serializeSpecialFloatingPointValues().create();
float negativeInfinity = Float.NEGATIVE_INFINITY; float negativeInfinity = Float.NEGATIVE_INFINITY;
assertEquals("-Infinity", gson.toJson(negativeInfinity)); assertEquals("-Infinity", gson.toJson(negativeInfinity));
assertEquals("-Infinity", gson.toJson(Float.NEGATIVE_INFINITY)); assertEquals("-Infinity", gson.toJson(Float.NEGATIVE_INFINITY));
@ -633,9 +629,9 @@ public class PrimitiveTest extends TestCase {
String value = "String Blah Blah Blah...1, 2, 3"; String value = "String Blah Blah Blah...1, 2, 3";
try { try {
gson.fromJson(value, String.class); new Gson().fromJson(value, String.class);
fail(); fail();
} catch (JsonSyntaxException expected) { } } catch (JsonIOException expected) { }
} }
public void testHtmlCharacterSerialization() throws Exception { public void testHtmlCharacterSerialization() throws Exception {

View File

@ -38,7 +38,7 @@ public class SecurityTest extends TestCase {
@Override @Override
protected void setUp() throws Exception { protected void setUp() throws Exception {
super.setUp(); super.setUp();
gsonBuilder = new GsonBuilder(); gsonBuilder = new GsonBuilder().setLenient();
} }
public void testNonExecutableJsonSerialization() { public void testNonExecutableJsonSerialization() {

View File

@ -159,7 +159,7 @@ public final class StreamingTypeAdaptersTest extends TestCase {
out.value(person.name + "," + person.age); out.value(person.name + "," + person.age);
} }
}; };
Gson gson = new GsonBuilder().registerTypeAdapter( Gson gson = new GsonBuilder().setLenient().registerTypeAdapter(
Person.class, typeAdapter).create(); Person.class, typeAdapter).create();
Truck truck = new Truck(); Truck truck = new Truck();
truck.horsePower = 1.0D; truck.horsePower = 1.0D;
@ -175,7 +175,7 @@ public final class StreamingTypeAdaptersTest extends TestCase {
gson.fromJson(json, Truck.class); gson.fromJson(json, Truck.class);
fail(); fail();
} catch (JsonSyntaxException expected) {} } catch (JsonSyntaxException expected) {}
gson = new GsonBuilder().registerTypeAdapter(Person.class, typeAdapter.nullSafe()).create(); gson = new GsonBuilder().setLenient().registerTypeAdapter(Person.class, typeAdapter.nullSafe()).create();
assertEquals("{\"horsePower\":1.0,\"passengers\":[null,\"jesse,30\"]}", assertEquals("{\"horsePower\":1.0,\"passengers\":[null,\"jesse,30\"]}",
gson.toJson(truck, Truck.class)); gson.toJson(truck, Truck.class));
truck = gson.fromJson(json, Truck.class); truck = gson.fromJson(json, Truck.class);

View File

@ -54,6 +54,7 @@ public class TreeTypeAdaptersTest extends TestCase {
@Override @Override
protected void setUp() { protected void setUp() {
gson = new GsonBuilder() gson = new GsonBuilder()
.setLenient()
.registerTypeAdapter(Id.class, new IdTreeTypeAdapter()) .registerTypeAdapter(Id.class, new IdTreeTypeAdapter())
.create(); .create();
course = new Course<>(COURSE_ID, 4, course = new Course<>(COURSE_ID, 4,

View File

@ -34,6 +34,7 @@ import junit.framework.TestCase;
public final class TypeAdapterPrecedenceTest extends TestCase { public final class TypeAdapterPrecedenceTest extends TestCase {
public void testNonstreamingFollowedByNonstreaming() { public void testNonstreamingFollowedByNonstreaming() {
Gson gson = new GsonBuilder() Gson gson = new GsonBuilder()
.setLenient()
.registerTypeAdapter(Foo.class, newSerializer("serializer 1")) .registerTypeAdapter(Foo.class, newSerializer("serializer 1"))
.registerTypeAdapter(Foo.class, newSerializer("serializer 2")) .registerTypeAdapter(Foo.class, newSerializer("serializer 2"))
.registerTypeAdapter(Foo.class, newDeserializer("deserializer 1")) .registerTypeAdapter(Foo.class, newDeserializer("deserializer 1"))
@ -45,6 +46,7 @@ public final class TypeAdapterPrecedenceTest extends TestCase {
public void testStreamingFollowedByStreaming() { public void testStreamingFollowedByStreaming() {
Gson gson = new GsonBuilder() Gson gson = new GsonBuilder()
.setLenient()
.registerTypeAdapter(Foo.class, newTypeAdapter("type adapter 1")) .registerTypeAdapter(Foo.class, newTypeAdapter("type adapter 1"))
.registerTypeAdapter(Foo.class, newTypeAdapter("type adapter 2")) .registerTypeAdapter(Foo.class, newTypeAdapter("type adapter 2"))
.create(); .create();
@ -54,6 +56,7 @@ public final class TypeAdapterPrecedenceTest extends TestCase {
public void testSerializeNonstreamingTypeAdapterFollowedByStreamingTypeAdapter() { public void testSerializeNonstreamingTypeAdapterFollowedByStreamingTypeAdapter() {
Gson gson = new GsonBuilder() Gson gson = new GsonBuilder()
.setLenient()
.registerTypeAdapter(Foo.class, newSerializer("serializer")) .registerTypeAdapter(Foo.class, newSerializer("serializer"))
.registerTypeAdapter(Foo.class, newDeserializer("deserializer")) .registerTypeAdapter(Foo.class, newDeserializer("deserializer"))
.registerTypeAdapter(Foo.class, newTypeAdapter("type adapter")) .registerTypeAdapter(Foo.class, newTypeAdapter("type adapter"))
@ -64,6 +67,7 @@ public final class TypeAdapterPrecedenceTest extends TestCase {
public void testStreamingFollowedByNonstreaming() { public void testStreamingFollowedByNonstreaming() {
Gson gson = new GsonBuilder() Gson gson = new GsonBuilder()
.setLenient()
.registerTypeAdapter(Foo.class, newTypeAdapter("type adapter")) .registerTypeAdapter(Foo.class, newTypeAdapter("type adapter"))
.registerTypeAdapter(Foo.class, newSerializer("serializer")) .registerTypeAdapter(Foo.class, newSerializer("serializer"))
.registerTypeAdapter(Foo.class, newDeserializer("deserializer")) .registerTypeAdapter(Foo.class, newDeserializer("deserializer"))
@ -74,6 +78,7 @@ public final class TypeAdapterPrecedenceTest extends TestCase {
public void testStreamingHierarchicalFollowedByNonstreaming() { public void testStreamingHierarchicalFollowedByNonstreaming() {
Gson gson = new GsonBuilder() Gson gson = new GsonBuilder()
.setLenient()
.registerTypeHierarchyAdapter(Foo.class, newTypeAdapter("type adapter")) .registerTypeHierarchyAdapter(Foo.class, newTypeAdapter("type adapter"))
.registerTypeAdapter(Foo.class, newSerializer("serializer")) .registerTypeAdapter(Foo.class, newSerializer("serializer"))
.registerTypeAdapter(Foo.class, newDeserializer("deserializer")) .registerTypeAdapter(Foo.class, newDeserializer("deserializer"))
@ -89,11 +94,12 @@ public final class TypeAdapterPrecedenceTest extends TestCase {
.registerTypeHierarchyAdapter(Foo.class, newDeserializer("deserializer")) .registerTypeHierarchyAdapter(Foo.class, newDeserializer("deserializer"))
.create(); .create();
assertEquals("\"foo via type adapter\"", gson.toJson(new Foo("foo"))); assertEquals("\"foo via type adapter\"", gson.toJson(new Foo("foo")));
assertEquals("foo via type adapter", gson.fromJson("foo", Foo.class).name); assertEquals("foo via type adapter", gson.fromJson("\"foo\"", Foo.class).name);
} }
public void testStreamingHierarchicalFollowedByNonstreamingHierarchical() { public void testStreamingHierarchicalFollowedByNonstreamingHierarchical() {
Gson gson = new GsonBuilder() Gson gson = new GsonBuilder()
.setLenient()
.registerTypeHierarchyAdapter(Foo.class, newSerializer("serializer")) .registerTypeHierarchyAdapter(Foo.class, newSerializer("serializer"))
.registerTypeHierarchyAdapter(Foo.class, newDeserializer("deserializer")) .registerTypeHierarchyAdapter(Foo.class, newDeserializer("deserializer"))
.registerTypeHierarchyAdapter(Foo.class, newTypeAdapter("type adapter")) .registerTypeHierarchyAdapter(Foo.class, newTypeAdapter("type adapter"))
@ -104,6 +110,7 @@ public final class TypeAdapterPrecedenceTest extends TestCase {
public void testNonstreamingHierarchicalFollowedByNonstreaming() { public void testNonstreamingHierarchicalFollowedByNonstreaming() {
Gson gson = new GsonBuilder() Gson gson = new GsonBuilder()
.setLenient()
.registerTypeHierarchyAdapter(Foo.class, newSerializer("hierarchical")) .registerTypeHierarchyAdapter(Foo.class, newSerializer("hierarchical"))
.registerTypeHierarchyAdapter(Foo.class, newDeserializer("hierarchical")) .registerTypeHierarchyAdapter(Foo.class, newDeserializer("hierarchical"))
.registerTypeAdapter(Foo.class, newSerializer("non hierarchical")) .registerTypeAdapter(Foo.class, newSerializer("non hierarchical"))

View File

@ -52,7 +52,7 @@ public class SqlTypesGsonTest extends TestCase {
} }
public void testDefaultSqlDateDeserialization() { public void testDefaultSqlDateDeserialization() {
String json = "'Dec 3, 2009'"; String json = "\"Dec 3, 2009\"";
java.sql.Date extracted = gson.fromJson(json, java.sql.Date.class); java.sql.Date extracted = gson.fromJson(json, java.sql.Date.class);
DefaultTypeAdaptersTest.assertEqualsDate(extracted, 2009, 11, 3); DefaultTypeAdaptersTest.assertEqualsDate(extracted, 2009, 11, 3);
} }
@ -82,7 +82,7 @@ public class SqlTypesGsonTest extends TestCase {
} }
public void testDefaultSqlTimeDeserialization() { public void testDefaultSqlTimeDeserialization() {
String json = "'1:18:02 PM'"; String json = "\"1:18:02 PM\"";
Time extracted = gson.fromJson(json, Time.class); Time extracted = gson.fromJson(json, Time.class);
DefaultTypeAdaptersTest.assertEqualsTime(extracted, 13, 18, 2); DefaultTypeAdaptersTest.assertEqualsTime(extracted, 13, 18, 2);
} }
@ -98,7 +98,7 @@ public class SqlTypesGsonTest extends TestCase {
} }
public void testDefaultSqlTimestampDeserialization() { public void testDefaultSqlTimestampDeserialization() {
String json = "'Dec 3, 2009 1:18:02 PM'"; String json = "\"Dec 3, 2009 1:18:02 PM\"";
Timestamp extracted = gson.fromJson(json, Timestamp.class); Timestamp extracted = gson.fromJson(json, Timestamp.class);
DefaultTypeAdaptersTest.assertEqualsDate(extracted, 2009, 11, 3); DefaultTypeAdaptersTest.assertEqualsDate(extracted, 2009, 11, 3);
DefaultTypeAdaptersTest.assertEqualsTime(extracted, 13, 18, 2); DefaultTypeAdaptersTest.assertEqualsTime(extracted, 13, 18, 2);

View File

@ -14,8 +14,9 @@
* limitations under the License. * limitations under the License.
*/ */
package com.google.gson; package com.google.gson.jf;
import com.google.gson.*;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@ -39,7 +40,7 @@ public final class CommentsTest extends TestCase {
+ " \"c\"\n" + " \"c\"\n"
+ "]"; + "]";
List<String> abc = new Gson().fromJson(json, new TypeToken<List<String>>() {}.getType()); List<String> abc = new GsonBuilder().setLenient().create().fromJson(json, new TypeToken<List<String>>() {}.getType());
assertEquals(Arrays.asList("a", "b", "c"), abc); assertEquals(Arrays.asList("a", "b", "c"), abc);
} }
} }

View File

@ -0,0 +1,28 @@
package com.google.gson.jf;
import junit.framework.*;
import java.util.*;
public class ExtraAssert {
public static <T> void assertListEquals(List<T> expecteds, List<T> actuals) {
TestCase.assertNotNull(expecteds);
TestCase.assertNotNull(actuals);
TestCase.assertEquals(expecteds.size(), actuals.size());
for (int i = 0; i < expecteds.size(); i++) {
TestCase.assertEquals(expecteds.get(i), actuals.get(i));
}
}
public static class StringArrayBox {
public String[] collection;
}
public static class StringListBox {
public List<String> collection;
}
public static class IntListBox {
public List<Integer> collection;
}
}

View File

@ -0,0 +1,49 @@
package com.google.gson.jf;
import com.google.gson.*;
import junit.framework.*;
public class Json5Test extends TestCase {
public void testShortExample() {
// Taken from the official example
assertTrue(new Gson().fromJson("{\n" +
" // comments\n" +
" unquoted: 'and you can quote me on that',\n" +
" singleQuotes: 'I can use \"double quotes\" here',\n" +
" lineBreaks: \"Look, Mom! \\\n" +
"No \\\\n's!\",\n" +
" hexadecimal: 0xdecaf,\n" +
" leadingDecimalPoint: .8675309, andTrailing: 8675309.,\n" +
" positiveSign: +1,\n" +
" trailingComma: 'in objects', andIn: ['arrays',],\n" +
" \"backwardsCompatible\": \"with JSON\",\n" +
"}", ExampleModel.class).isDefault());
}
public static class ExampleModel {
public String unquoted;
public String singleQuotes;
public String lineBreaks;
public Integer hexadecimal;
public Double leadingDecimalPoint;
public Double andTrailing;
public Integer positiveSign;
public String trailingComma;
public String[] andIn;
public String backwardsCompatible;
public boolean isDefault() {
return unquoted.equals("and you can quote me on that")
&& singleQuotes.equals("I can use \"double quotes\" here")
&& lineBreaks.equals("Look, Mom!\nNo \\n's!")
&& hexadecimal.equals(0xdecaf)
&& leadingDecimalPoint.equals(.8675309)
&& andTrailing.equals(8675309.)
&& positiveSign.equals(1)
&& trailingComma.equals("in objects")
&& andIn.length == 1 && andIn[0].equals("arrays")
&& backwardsCompatible.equals("with JSON");
}
}
}

View File

@ -0,0 +1,22 @@
package com.google.gson.jf;
import com.google.gson.*;
import junit.framework.TestCase;
import java.util.*;
import static com.google.gson.jf.ExtraAssert.*;
public class LenientCollectionCommaTest extends TestCase {
private Gson lenient;
private static final String json = "{\"collection\": [1, 2,, 3, , , 4, 5,]}";
@Override
protected void setUp() throws Exception {
super.setUp();
lenient = new GsonBuilder().setLenient().create();
}
public void testElementSkipping() {
assertListEquals(List.of(1, 2, 3, 4, 5), lenient.fromJson(json, IntListBox.class).collection);
}
}

View File

@ -0,0 +1,45 @@
package com.google.gson.jf;
import com.google.gson.*;
import junit.framework.TestCase;
import java.util.*;
import static org.junit.Assert.*;
import static com.google.gson.jf.ExtraAssert.*;
public class LenientCollectionTest extends TestCase {
private Gson lenient;
private Gson strict;
private static final String json = "{\"collection\": \"example\"}";
@Override
protected void setUp() throws Exception {
super.setUp();
lenient = new GsonBuilder().setLenient().create();
strict = new GsonBuilder().create();
}
public void testLenientArray() {
assertArrayEquals(new String[] {"example"}, lenient.fromJson(json, StringArrayBox.class).collection);
}
public void testLenientList() {
assertListEquals(List.of("example"), lenient.fromJson(json, StringListBox.class).collection);
}
public void testStrictArray() {
try {
strict.fromJson(json, StringArrayBox.class);
fail("Strict Gson should not deserialize array without brackets");
} catch (JsonParseException expected) {
}
}
public void testStrictList() {
try {
strict.fromJson(json, StringListBox.class);
fail("Strict Gson should not deserialize list without brackets");
} catch (JsonParseException expected) {
}
}
}

View File

@ -0,0 +1,33 @@
package com.google.gson.jf;
import com.google.gson.*;
import junit.framework.*;
import java.util.*;
import static com.google.gson.jf.ExtraAssert.*;
public class OmitQuotesTest extends TestCase {
private Gson lenient;
private Gson strict;
private static final String lenientJson = "{collection:[\"example\"]}";
private static final String strictJson = "{\"collection\":[\"example\"]}";
private StringListBox slb;
@Override
protected void setUp() throws Exception {
super.setUp();
lenient = new GsonBuilder().setOmitQuotes().create();
strict = new GsonBuilder().create();
slb = new StringListBox();
slb.collection = List.of("example");
}
public void testLenient() {
assertEquals(lenientJson, lenient.toJson(slb));
}
public void testStrict() {
assertEquals(strictJson, strict.toJson(slb));
}
}

View File

@ -32,7 +32,7 @@ public class JsonAdapterNullSafeTest extends TestCase {
} }
public void testNullSafeBugDeserialize() throws Exception { public void testNullSafeBugDeserialize() throws Exception {
Device device = gson.fromJson("{'id':'ec57803e2'}", Device.class); Device device = gson.fromJson("{\"id\":\"ec57803e2\"}", Device.class);
assertEquals("ec57803e2", device.id); assertEquals("ec57803e2", device.id);
} }

View File

@ -1172,7 +1172,7 @@ public final class JsonReaderTest extends TestCase {
try { try {
reader.nextNull(); reader.nextNull();
fail(); fail();
} catch (IOException expected) { } catch (IllegalStateException expected) {
} }
reader = new JsonReader(reader("[,]")); reader = new JsonReader(reader("[,]"));
@ -1189,14 +1189,14 @@ public final class JsonReaderTest extends TestCase {
reader.setLenient(true); reader.setLenient(true);
reader.beginArray(); reader.beginArray();
assertEquals(true, reader.nextBoolean()); assertEquals(true, reader.nextBoolean());
reader.nextNull(); //reader.nextNull();
assertEquals(true, reader.nextBoolean()); assertEquals(true, reader.nextBoolean());
reader.endArray(); reader.endArray();
reader = new JsonReader(reader("[,true]")); reader = new JsonReader(reader("[,true]"));
reader.setLenient(true); reader.setLenient(true);
reader.beginArray(); reader.beginArray();
reader.nextNull(); //reader.nextNull();
assertEquals(true, reader.nextBoolean()); assertEquals(true, reader.nextBoolean());
reader.endArray(); reader.endArray();
@ -1204,14 +1204,14 @@ public final class JsonReaderTest extends TestCase {
reader.setLenient(true); reader.setLenient(true);
reader.beginArray(); reader.beginArray();
assertEquals(true, reader.nextBoolean()); assertEquals(true, reader.nextBoolean());
reader.nextNull(); //reader.nextNull();
reader.endArray(); reader.endArray();
reader = new JsonReader(reader("[,]")); reader = new JsonReader(reader("[,]"));
reader.setLenient(true); reader.setLenient(true);
reader.beginArray(); reader.beginArray();
reader.nextNull(); //reader.nextNull();
reader.nextNull(); //reader.nextNull();
reader.endArray(); reader.endArray();
} }
@ -1239,7 +1239,7 @@ public final class JsonReaderTest extends TestCase {
try { try {
reader.skipValue(); reader.skipValue();
fail(); fail();
} catch (IOException expected) { } catch (IllegalStateException expected) {
} }
reader = new JsonReader(reader("[,]")); reader = new JsonReader(reader("[,]"));
@ -1379,46 +1379,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 path $[1]", testFailWithPosition("Expected value at line 6 column 5 (char '}') 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 path $[1]", testFailWithPosition("Expected value at line 6 column 5 (char '}') 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 path $[1]", testFailWithPosition("Expected value at line 5 column 6 (char '}') 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 path $[1]", testFailWithPosition("Expected value at line 5 column 6 (char '}') 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 path $[1]", testFailWithPosition("Expected value at line 6 column 12 (char '}') 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 path $[1]", testFailWithPosition("Expected value at line 5 column 3 (char '}') path $[1]",
"[\"foo\nbar\r\nbaz\n\",\n }"); "[\"foo\nbar\r\nbaz\n\",\n }");
} }
public void testFailWithPositionOverUnquotedString() throws IOException { public void testFailWithPositionOverUnquotedString() throws IOException {
testFailWithPosition("Expected value at line 5 column 2 path $[1]", "[\n\nabcd\n\n,}"); testFailWithPosition("Expected value at line 5 column 2 (char '}') path $[1]", "[\n\nabcd\n\n,}");
} }
public void testFailWithEscapedNewlineCharacter() throws IOException { public void testFailWithEscapedNewlineCharacter() throws IOException {
testFailWithPosition("Expected value at line 5 column 3 path $[1]", "[\n\n\"\\\n\n\",}"); testFailWithPosition("Expected value at line 5 column 3 (char '}') path $[1]", "[\n\n\"\\\n\n\",}");
} }
public void testFailWithPositionIsOffsetByBom() throws IOException { public void testFailWithPositionIsOffsetByBom() throws IOException {
testFailWithPosition("Expected value at line 1 column 6 path $[1]", testFailWithPosition("Expected value at line 1 column 6 (char '}') path $[1]",
"\ufeff[\"a\",}]"); "\ufeff[\"a\",}]");
} }
@ -1461,7 +1461,7 @@ public final class JsonReaderTest extends TestCase {
reader.peek(); reader.peek();
fail(); fail();
} catch (IOException expected) { } catch (IOException expected) {
assertEquals("Expected value at line 1 column 14 path $[1].a[2]", expected.getMessage()); assertEquals("Expected value at line 1 column 14 (char '}') path $[1].a[2]", expected.getMessage());
} }
} }
@ -1728,7 +1728,7 @@ public final class JsonReaderTest extends TestCase {
assertDocument("{\"name\"=>\"string\",", BEGIN_OBJECT, NAME, STRING, IOException.class); assertDocument("{\"name\"=>\"string\",", BEGIN_OBJECT, NAME, STRING, IOException.class);
assertDocument("{\"name\"=>\"string\",\"name\"", BEGIN_OBJECT, NAME, STRING, NAME); assertDocument("{\"name\"=>\"string\",\"name\"", BEGIN_OBJECT, NAME, STRING, NAME);
assertDocument("[}", BEGIN_ARRAY, IOException.class); assertDocument("[}", BEGIN_ARRAY, IOException.class);
assertDocument("[,]", BEGIN_ARRAY, NULL, NULL, END_ARRAY); assertDocument("[,]", BEGIN_ARRAY, END_ARRAY);
assertDocument("{", BEGIN_OBJECT, IOException.class); assertDocument("{", BEGIN_OBJECT, IOException.class);
assertDocument("{\"name\"", BEGIN_OBJECT, NAME, IOException.class); assertDocument("{\"name\"", BEGIN_OBJECT, NAME, IOException.class);
assertDocument("{\"name\",", BEGIN_OBJECT, NAME, IOException.class); assertDocument("{\"name\",", BEGIN_OBJECT, NAME, IOException.class);