Add newBuilder() API (#1142)

* Add Gson.newBuilder API.

* Remove redundant test.

* Address Codacy comments.

* Reduce visibility of GsonBuilder constructor.
This commit is contained in:
Warren Smith 2017-09-20 18:53:10 -07:00 committed by inder123
parent a8f7acd618
commit 08bbb226f1
3 changed files with 105 additions and 18 deletions

View File

@ -25,6 +25,7 @@ import java.io.Writer;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.BigInteger; import java.math.BigInteger;
import java.text.DateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
@ -124,18 +125,28 @@ public final class Gson {
private final Map<TypeToken<?>, TypeAdapter<?>> typeTokenCache = new ConcurrentHashMap<TypeToken<?>, TypeAdapter<?>>(); private final Map<TypeToken<?>, TypeAdapter<?>> typeTokenCache = new ConcurrentHashMap<TypeToken<?>, TypeAdapter<?>>();
private final List<TypeAdapterFactory> factories;
private final ConstructorConstructor constructorConstructor; private final ConstructorConstructor constructorConstructor;
private final Excluder excluder;
private final FieldNamingStrategy fieldNamingStrategy;
private final boolean serializeNulls;
private final boolean htmlSafe;
private final boolean generateNonExecutableJson;
private final boolean prettyPrinting;
private final boolean lenient;
private final JsonAdapterAnnotationTypeAdapterFactory jsonAdapterFactory; private final JsonAdapterAnnotationTypeAdapterFactory jsonAdapterFactory;
final List<TypeAdapterFactory> factories;
final Excluder excluder;
final FieldNamingStrategy fieldNamingStrategy;
final Map<Type, InstanceCreator<?>> instanceCreators;
final boolean serializeNulls;
final boolean complexMapKeySerialization;
final boolean generateNonExecutableJson;
final boolean htmlSafe;
final boolean prettyPrinting;
final boolean lenient;
final boolean serializeSpecialFloatingPointValues;
final String datePattern;
final int dateStyle;
final int timeStyle;
final LongSerializationPolicy longSerializationPolicy;
final List<TypeAdapterFactory> builderFactories;
final List<TypeAdapterFactory> builderHierarchyFactories;
/** /**
* Constructs a Gson object with default configuration. The default configuration has the * Constructs a Gson object with default configuration. The default configuration has the
* following settings: * following settings:
@ -175,23 +186,36 @@ public final class Gson {
Collections.<Type, InstanceCreator<?>>emptyMap(), DEFAULT_SERIALIZE_NULLS, Collections.<Type, InstanceCreator<?>>emptyMap(), DEFAULT_SERIALIZE_NULLS,
DEFAULT_COMPLEX_MAP_KEYS, DEFAULT_JSON_NON_EXECUTABLE, DEFAULT_ESCAPE_HTML, DEFAULT_COMPLEX_MAP_KEYS, DEFAULT_JSON_NON_EXECUTABLE, DEFAULT_ESCAPE_HTML,
DEFAULT_PRETTY_PRINT, DEFAULT_LENIENT, DEFAULT_SPECIALIZE_FLOAT_VALUES, DEFAULT_PRETTY_PRINT, DEFAULT_LENIENT, DEFAULT_SPECIALIZE_FLOAT_VALUES,
LongSerializationPolicy.DEFAULT, Collections.<TypeAdapterFactory>emptyList()); LongSerializationPolicy.DEFAULT, null, DateFormat.DEFAULT, DateFormat.DEFAULT,
Collections.<TypeAdapterFactory>emptyList(), Collections.<TypeAdapterFactory>emptyList(),
Collections.<TypeAdapterFactory>emptyList());
} }
Gson(final Excluder excluder, final FieldNamingStrategy fieldNamingStrategy, Gson(final Excluder excluder, final FieldNamingStrategy fieldNamingStrategy,
final Map<Type, InstanceCreator<?>> instanceCreators, boolean serializeNulls, final Map<Type, InstanceCreator<?>> instanceCreators, boolean serializeNulls,
boolean complexMapKeySerialization, boolean generateNonExecutableGson, boolean htmlSafe, boolean complexMapKeySerialization, boolean generateNonExecutableGson, boolean htmlSafe,
boolean prettyPrinting, boolean lenient, boolean serializeSpecialFloatingPointValues, boolean prettyPrinting, boolean lenient, boolean serializeSpecialFloatingPointValues,
LongSerializationPolicy longSerializationPolicy, LongSerializationPolicy longSerializationPolicy, String datePattern, int dateStyle,
List<TypeAdapterFactory> typeAdapterFactories) { int timeStyle, List<TypeAdapterFactory> builderFactories,
this.constructorConstructor = new ConstructorConstructor(instanceCreators); List<TypeAdapterFactory> builderHierarchyFactories,
List<TypeAdapterFactory> factoriesToBeAdded) {
this.excluder = excluder; this.excluder = excluder;
this.fieldNamingStrategy = fieldNamingStrategy; this.fieldNamingStrategy = fieldNamingStrategy;
this.instanceCreators = instanceCreators;
this.constructorConstructor = new ConstructorConstructor(instanceCreators);
this.serializeNulls = serializeNulls; this.serializeNulls = serializeNulls;
this.complexMapKeySerialization = complexMapKeySerialization;
this.generateNonExecutableJson = generateNonExecutableGson; this.generateNonExecutableJson = generateNonExecutableGson;
this.htmlSafe = htmlSafe; this.htmlSafe = htmlSafe;
this.prettyPrinting = prettyPrinting; this.prettyPrinting = prettyPrinting;
this.lenient = lenient; this.lenient = lenient;
this.serializeSpecialFloatingPointValues = serializeSpecialFloatingPointValues;
this.longSerializationPolicy = longSerializationPolicy;
this.datePattern = datePattern;
this.dateStyle = dateStyle;
this.timeStyle = timeStyle;
this.builderFactories = builderFactories;
this.builderHierarchyFactories = builderHierarchyFactories;
List<TypeAdapterFactory> factories = new ArrayList<TypeAdapterFactory>(); List<TypeAdapterFactory> factories = new ArrayList<TypeAdapterFactory>();
@ -202,8 +226,8 @@ public final class Gson {
// the excluder must precede all adapters that handle user-defined types // the excluder must precede all adapters that handle user-defined types
factories.add(excluder); factories.add(excluder);
// user's type adapters // users' type adapters
factories.addAll(typeAdapterFactories); factories.addAll(factoriesToBeAdded);
// type adapters for basic platform types // type adapters for basic platform types
factories.add(TypeAdapters.STRING_FACTORY); factories.add(TypeAdapters.STRING_FACTORY);
@ -255,6 +279,16 @@ public final class Gson {
this.factories = Collections.unmodifiableList(factories); this.factories = Collections.unmodifiableList(factories);
} }
/**
* Returns a new GsonBuilder containing all custom factories and configuration used by the current
* instance.
*
* @return a GsonBuilder instance.
*/
public GsonBuilder newBuilder() {
return new GsonBuilder(this);
}
public Excluder excluder() { public Excluder excluder() {
return excluder; return excluder;
} }

View File

@ -104,6 +104,31 @@ public final class GsonBuilder {
public GsonBuilder() { public GsonBuilder() {
} }
/**
* Constructs a GsonBuilder instance from a Gson instance. The newly constructed GsonBuilder
* has the same configuration as the previously built Gson instance.
*
* @param gson the gson instance whose configuration should by applied to a new GsonBuilder.
*/
GsonBuilder(Gson gson) {
this.excluder = gson.excluder;
this.fieldNamingPolicy = gson.fieldNamingStrategy;
this.instanceCreators.putAll(gson.instanceCreators);
this.serializeNulls = gson.serializeNulls;
this.complexMapKeySerialization = gson.complexMapKeySerialization;
this.generateNonExecutableJson = gson.generateNonExecutableJson;
this.escapeHtmlChars = gson.htmlSafe;
this.prettyPrinting = gson.prettyPrinting;
this.lenient = gson.lenient;
this.serializeSpecialFloatingPointValues = gson.serializeSpecialFloatingPointValues;
this.longSerializationPolicy = gson.longSerializationPolicy;
this.datePattern = gson.datePattern;
this.dateStyle = gson.dateStyle;
this.timeStyle = gson.timeStyle;
this.factories.addAll(gson.builderFactories);
this.hierarchyFactories.addAll(gson.builderHierarchyFactories);
}
/** /**
* Configures Gson to enable versioning support. * Configures Gson to enable versioning support.
* *
@ -572,7 +597,9 @@ public final class GsonBuilder {
return new Gson(excluder, fieldNamingPolicy, instanceCreators, return new Gson(excluder, fieldNamingPolicy, instanceCreators,
serializeNulls, complexMapKeySerialization, serializeNulls, complexMapKeySerialization,
generateNonExecutableJson, escapeHtmlChars, prettyPrinting, lenient, generateNonExecutableJson, escapeHtmlChars, prettyPrinting, lenient,
serializeSpecialFloatingPointValues, longSerializationPolicy, factories); serializeSpecialFloatingPointValues, longSerializationPolicy,
datePattern, dateStyle, timeStyle,
this.factories, this.hierarchyFactories, factories);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")

View File

@ -17,8 +17,12 @@
package com.google.gson; package com.google.gson;
import com.google.gson.internal.Excluder; import com.google.gson.internal.Excluder;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.text.DateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import junit.framework.TestCase; import junit.framework.TestCase;
@ -43,12 +47,34 @@ 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, true, false, new HashMap<Type, InstanceCreator<?>>(), true, false, true, false,
true, true, false, LongSerializationPolicy.DEFAULT, true, true, false, LongSerializationPolicy.DEFAULT, null, DateFormat.DEFAULT,
new ArrayList<TypeAdapterFactory>()); DateFormat.DEFAULT, new ArrayList<TypeAdapterFactory>(),
new ArrayList<TypeAdapterFactory>(), new ArrayList<TypeAdapterFactory>());
assertEquals(CUSTOM_EXCLUDER, gson.excluder()); assertEquals(CUSTOM_EXCLUDER, gson.excluder());
assertEquals(CUSTOM_FIELD_NAMING_STRATEGY, gson.fieldNamingStrategy()); assertEquals(CUSTOM_FIELD_NAMING_STRATEGY, gson.fieldNamingStrategy());
assertEquals(true, gson.serializeNulls()); assertEquals(true, gson.serializeNulls());
assertEquals(false, gson.htmlSafe()); assertEquals(false, gson.htmlSafe());
} }
public void testClonedTypeAdapterFactoryListsAreIndependent() {
Gson original = new Gson(CUSTOM_EXCLUDER, CUSTOM_FIELD_NAMING_STRATEGY,
new HashMap<Type, InstanceCreator<?>>(), true, false, true, false,
true, true, false, LongSerializationPolicy.DEFAULT, null, DateFormat.DEFAULT,
DateFormat.DEFAULT, new ArrayList<TypeAdapterFactory>(),
new ArrayList<TypeAdapterFactory>(), new ArrayList<TypeAdapterFactory>());
Gson clone = original.newBuilder()
.registerTypeAdapter(Object.class, new TestTypeAdapter())
.create();
assertEquals(original.factories.size() + 1, clone.factories.size());
}
private static final class TestTypeAdapter extends TypeAdapter<Object> {
@Override public void write(JsonWriter out, Object value) throws IOException {
// Test stub.
}
@Override public Object read(JsonReader in) throws IOException { return null; }
}
} }