Add setting for leniency on Gson instance.

Add a JsonReader factory (for parity with the JsonWriter one) which provides a configured instance using the Gson settings.
This commit is contained in:
Jake Wharton 2016-01-17 03:03:04 -05:00
parent 34f4005829
commit 3360c93a76
4 changed files with 101 additions and 14 deletions

View File

@ -101,6 +101,12 @@ import com.google.gson.stream.MalformedJsonException;
*/
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_SPECIALIZE_FLOAT_VALUES = false;
private static final String JSON_NON_EXECUTABLE_PREFIX = ")]}'\n";
@ -124,6 +130,7 @@ public final class Gson {
private final boolean htmlSafe;
private final boolean generateNonExecutableJson;
private final boolean prettyPrinting;
private final boolean lenient;
final JsonDeserializationContext deserializationContext = new JsonDeserializationContext() {
@SuppressWarnings("unchecked")
@ -177,15 +184,16 @@ public final class Gson {
*/
public Gson() {
this(Excluder.DEFAULT, FieldNamingPolicy.IDENTITY,
Collections.<Type, InstanceCreator<?>>emptyMap(), false, false, DEFAULT_JSON_NON_EXECUTABLE,
true, false, false, LongSerializationPolicy.DEFAULT,
Collections.<TypeAdapterFactory>emptyList());
Collections.<Type, InstanceCreator<?>>emptyMap(), DEFAULT_SERIALIZE_NULLS,
DEFAULT_COMPLEX_MAP_KEYS, DEFAULT_JSON_NON_EXECUTABLE, DEFAULT_ESCAPE_HTML,
DEFAULT_PRETTY_PRINT, DEFAULT_LENIENT, DEFAULT_SPECIALIZE_FLOAT_VALUES,
LongSerializationPolicy.DEFAULT, Collections.<TypeAdapterFactory>emptyList());
}
Gson(final Excluder excluder, final FieldNamingStrategy fieldNamingPolicy,
final Map<Type, InstanceCreator<?>> instanceCreators, boolean serializeNulls,
boolean complexMapKeySerialization, boolean generateNonExecutableGson, boolean htmlSafe,
boolean prettyPrinting, boolean serializeSpecialFloatingPointValues,
boolean prettyPrinting, boolean lenient, boolean serializeSpecialFloatingPointValues,
LongSerializationPolicy longSerializationPolicy,
List<TypeAdapterFactory> typeAdapterFactories) {
this.constructorConstructor = new ConstructorConstructor(instanceCreators);
@ -193,6 +201,7 @@ public final class Gson {
this.generateNonExecutableJson = generateNonExecutableGson;
this.htmlSafe = htmlSafe;
this.prettyPrinting = prettyPrinting;
this.lenient = lenient;
List<TypeAdapterFactory> factories = new ArrayList<TypeAdapterFactory>();
@ -704,6 +713,15 @@ public final class Gson {
return jsonWriter;
}
/**
* Returns a new JSON writer configured for the settings on this Gson instance.
*/
public JsonReader newJsonReader(Reader reader) {
JsonReader jsonReader = new JsonReader(reader);
jsonReader.setLenient(lenient);
return jsonReader;
}
/**
* Writes the JSON for {@code jsonElement} to {@code writer}.
* @throws JsonIOException if there was a problem writing to the writer
@ -795,7 +813,7 @@ public final class Gson {
* @since 1.2
*/
public <T> T fromJson(Reader json, Class<T> classOfT) throws JsonSyntaxException, JsonIOException {
JsonReader jsonReader = new JsonReader(json);
JsonReader jsonReader = newJsonReader(json);
Object object = fromJson(jsonReader, classOfT);
assertFullConsumption(object, jsonReader);
return Primitives.wrap(classOfT).cast(object);
@ -822,7 +840,7 @@ public final class Gson {
*/
@SuppressWarnings("unchecked")
public <T> T fromJson(Reader json, Type typeOfT) throws JsonIOException, JsonSyntaxException {
JsonReader jsonReader = new JsonReader(json);
JsonReader jsonReader = newJsonReader(json);
T object = (T) fromJson(jsonReader, typeOfT);
assertFullConsumption(object, jsonReader);
return object;

View File

@ -16,6 +16,7 @@
package com.google.gson;
import com.google.gson.stream.JsonReader;
import java.lang.reflect.Type;
import java.sql.Timestamp;
import java.text.DateFormat;
@ -31,6 +32,14 @@ import com.google.gson.internal.Excluder;
import com.google.gson.internal.bind.TypeAdapters;
import com.google.gson.reflect.TypeToken;
import static com.google.gson.Gson.DEFAULT_COMPLEX_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_PRETTY_PRINT;
import static com.google.gson.Gson.DEFAULT_SERIALIZE_NULLS;
import static com.google.gson.Gson.DEFAULT_SPECIALIZE_FLOAT_VALUES;
/**
* <p>Use this builder to construct a {@link Gson} instance when you need to set configuration
* options other than the default. For {@link Gson} with default configuration, it is simpler to
@ -74,15 +83,16 @@ public final class GsonBuilder {
private final List<TypeAdapterFactory> factories = new ArrayList<TypeAdapterFactory>();
/** tree-style hierarchy factories. These come after factories for backwards compatibility. */
private final List<TypeAdapterFactory> hierarchyFactories = new ArrayList<TypeAdapterFactory>();
private boolean serializeNulls;
private boolean serializeNulls = DEFAULT_SERIALIZE_NULLS;
private String datePattern;
private int dateStyle = DateFormat.DEFAULT;
private int timeStyle = DateFormat.DEFAULT;
private boolean complexMapKeySerialization;
private boolean serializeSpecialFloatingPointValues;
private boolean escapeHtmlChars = true;
private boolean prettyPrinting;
private boolean generateNonExecutableJson;
private boolean complexMapKeySerialization = DEFAULT_COMPLEX_MAP_KEYS;
private boolean serializeSpecialFloatingPointValues = DEFAULT_SPECIALIZE_FLOAT_VALUES;
private boolean escapeHtmlChars = DEFAULT_ESCAPE_HTML;
private boolean prettyPrinting = DEFAULT_PRETTY_PRINT;
private boolean generateNonExecutableJson = DEFAULT_JSON_NON_EXECUTABLE;
private boolean lenient = DEFAULT_LENIENT;
/**
* Creates a GsonBuilder instance that can be used to build Gson with various configuration
@ -351,6 +361,19 @@ public final class GsonBuilder {
return this;
}
/**
* By default, Gson is strict and only accepts JSON as specified by
* <a href="http://www.ietf.org/rfc/rfc4627.txt">RFC 4627</a>. This option makes the parser
* liberal in what it accepts.
*
* @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
* @see JsonReader#setLenient(boolean)
*/
public GsonBuilder setLenient() {
lenient = true;
return this;
}
/**
* By default, Gson escapes HTML characters such as &lt; &gt; etc. Use this option to configure
* Gson to pass-through HTML characters as is.
@ -544,7 +567,7 @@ public final class GsonBuilder {
return new Gson(excluder, fieldNamingPolicy, instanceCreators,
serializeNulls, complexMapKeySerialization,
generateNonExecutableJson, escapeHtmlChars, prettyPrinting,
generateNonExecutableJson, escapeHtmlChars, prettyPrinting, lenient,
serializeSpecialFloatingPointValues, longSerializationPolicy, factories);
}

View File

@ -294,7 +294,7 @@ public class JsonReader implements Closeable {
}
/**
* Configure this parser to be be liberal in what it accepts. By default,
* Configure this parser to be liberal in what it accepts. By default,
* this parser is strict and only accepts JSON as specified by <a
* href="http://www.ietf.org/rfc/rfc4627.txt">RFC 4627</a>. Setting the
* parser to lenient causes it to ignore the following syntax errors:

View File

@ -0,0 +1,46 @@
/*
* Copyright (C) 2016 The Gson Authors
*
* 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.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import java.util.List;
import junit.framework.TestCase;
import static java.util.Collections.singletonList;
/**
* Functional tests for leniency option.
*/
public class LeniencyTest extends TestCase {
private Gson gson;
@Override
protected void setUp() throws Exception {
super.setUp();
gson = new GsonBuilder().setLenient().create();
}
public void testLenientFromJson() {
List<String> json = gson.fromJson(""
+ "[ # One!\n"
+ " 'Hi' #Element!\n"
+ "] # Array!", new TypeToken<List<String>>() {}.getType());
assertEquals(singletonList("Hi"), json);
}
}