Skip to content

Commit 1db03ac

Browse files
Optimize new Gson()
Co-authored-by: Marcono1234 <[email protected]>
1 parent e28fdb9 commit 1db03ac

File tree

9 files changed

+423
-465
lines changed

9 files changed

+423
-465
lines changed

gson/src/main/java/com/google/gson/Gson.java

Lines changed: 33 additions & 311 deletions
Large diffs are not rendered by default.

gson/src/main/java/com/google/gson/GsonBuilder.java

Lines changed: 185 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -16,24 +16,20 @@
1616

1717
package com.google.gson;
1818

19-
import static com.google.gson.Gson.DEFAULT_COMPLEX_MAP_KEYS;
20-
import static com.google.gson.Gson.DEFAULT_DATE_PATTERN;
21-
import static com.google.gson.Gson.DEFAULT_ESCAPE_HTML;
22-
import static com.google.gson.Gson.DEFAULT_FORMATTING_STYLE;
23-
import static com.google.gson.Gson.DEFAULT_JSON_NON_EXECUTABLE;
24-
import static com.google.gson.Gson.DEFAULT_NUMBER_TO_NUMBER_STRATEGY;
25-
import static com.google.gson.Gson.DEFAULT_OBJECT_TO_NUMBER_STRATEGY;
26-
import static com.google.gson.Gson.DEFAULT_SERIALIZE_NULLS;
27-
import static com.google.gson.Gson.DEFAULT_SPECIALIZE_FLOAT_VALUES;
28-
import static com.google.gson.Gson.DEFAULT_STRICTNESS;
29-
import static com.google.gson.Gson.DEFAULT_USE_JDK_UNSAFE;
30-
3119
import com.google.errorprone.annotations.CanIgnoreReturnValue;
3220
import com.google.errorprone.annotations.InlineMe;
3321
import com.google.gson.annotations.Since;
3422
import com.google.gson.annotations.Until;
23+
import com.google.gson.internal.ConstructorConstructor;
3524
import com.google.gson.internal.Excluder;
25+
import com.google.gson.internal.bind.ArrayTypeAdapter;
26+
import com.google.gson.internal.bind.CollectionTypeAdapterFactory;
3627
import com.google.gson.internal.bind.DefaultDateTypeAdapter;
28+
import com.google.gson.internal.bind.JsonAdapterAnnotationTypeAdapterFactory;
29+
import com.google.gson.internal.bind.MapTypeAdapterFactory;
30+
import com.google.gson.internal.bind.NumberTypeAdapter;
31+
import com.google.gson.internal.bind.ObjectTypeAdapter;
32+
import com.google.gson.internal.bind.ReflectiveTypeAdapterFactory;
3733
import com.google.gson.internal.bind.TreeTypeAdapter;
3834
import com.google.gson.internal.bind.TypeAdapters;
3935
import com.google.gson.internal.sql.SqlTypesSupport;
@@ -45,12 +41,16 @@
4541
import java.text.SimpleDateFormat;
4642
import java.util.ArrayDeque;
4743
import java.util.ArrayList;
44+
import java.util.Arrays;
45+
import java.util.Collection;
4846
import java.util.Collections;
4947
import java.util.Date;
5048
import java.util.HashMap;
5149
import java.util.List;
5250
import java.util.Map;
5351
import java.util.Objects;
52+
import java.util.concurrent.atomic.AtomicLong;
53+
import java.util.concurrent.atomic.AtomicLongArray;
5454

5555
/**
5656
* Use this builder to construct a {@link Gson} instance when you need to set configuration options
@@ -90,29 +90,64 @@
9090
* @author Jesse Wilson
9191
*/
9292
public final class GsonBuilder {
93-
private Excluder excluder = Excluder.DEFAULT;
94-
private LongSerializationPolicy longSerializationPolicy = LongSerializationPolicy.DEFAULT;
95-
private FieldNamingStrategy fieldNamingPolicy = FieldNamingPolicy.IDENTITY;
96-
private final Map<Type, InstanceCreator<?>> instanceCreators = new HashMap<>();
97-
private final List<TypeAdapterFactory> factories = new ArrayList<>();
93+
private static final boolean DEFAULT_JSON_NON_EXECUTABLE = false;
94+
// Strictness of `null` is the legacy mode where some Gson APIs are always lenient
95+
private static final Strictness DEFAULT_STRICTNESS = null;
96+
private static final FormattingStyle DEFAULT_FORMATTING_STYLE = FormattingStyle.COMPACT;
97+
private static final boolean DEFAULT_ESCAPE_HTML = true;
98+
private static final boolean DEFAULT_SERIALIZE_NULLS = false;
99+
private static final boolean DEFAULT_COMPLEX_MAP_KEYS = false;
100+
private static final boolean DEFAULT_SPECIALIZE_FLOAT_VALUES = false;
101+
private static final boolean DEFAULT_USE_JDK_UNSAFE = true;
102+
private static final String DEFAULT_DATE_PATTERN = null;
103+
private static final FieldNamingStrategy DEFAULT_FIELD_NAMING_STRATEGY =
104+
FieldNamingPolicy.IDENTITY;
105+
private static final ToNumberStrategy DEFAULT_OBJECT_TO_NUMBER_STRATEGY = ToNumberPolicy.DOUBLE;
106+
private static final ToNumberStrategy DEFAULT_NUMBER_TO_NUMBER_STRATEGY =
107+
ToNumberPolicy.LAZILY_PARSED_NUMBER;
108+
109+
static final ConstructorConstructor DEFAULT_CONSTRUCTOR_CONSTRUCTOR =
110+
new ConstructorConstructor(
111+
Collections.emptyMap(), DEFAULT_USE_JDK_UNSAFE, Collections.emptyList());
112+
113+
static final JsonAdapterAnnotationTypeAdapterFactory
114+
DEFAULT_JSON_ADAPTER_ANNOTATION_TYPE_ADAPTER_FACTORY =
115+
new JsonAdapterAnnotationTypeAdapterFactory(DEFAULT_CONSTRUCTOR_CONSTRUCTOR);
116+
117+
/**
118+
* Default instance of the builder, to be used only by the default {@link Gson#Gson()}
119+
* constructor. Must not be used for anything else and must not be leaked to user code, since that
120+
* could lead to accidental modification of this default builder.
121+
*/
122+
static final GsonBuilder DEFAULT = new GsonBuilder();
123+
124+
static final List<TypeAdapterFactory> DEFAULT_TYPE_ADAPTER_FACTORIES =
125+
GsonBuilder.DEFAULT.createFactories(
126+
DEFAULT_CONSTRUCTOR_CONSTRUCTOR, DEFAULT_JSON_ADAPTER_ANNOTATION_TYPE_ADAPTER_FACTORY);
127+
128+
Excluder excluder = Excluder.DEFAULT;
129+
LongSerializationPolicy longSerializationPolicy = LongSerializationPolicy.DEFAULT;
130+
FieldNamingStrategy fieldNamingPolicy = DEFAULT_FIELD_NAMING_STRATEGY;
131+
final Map<Type, InstanceCreator<?>> instanceCreators = new HashMap<>();
132+
final List<TypeAdapterFactory> factories = new ArrayList<>();
98133

99134
/** tree-style hierarchy factories. These come after factories for backwards compatibility. */
100-
private final List<TypeAdapterFactory> hierarchyFactories = new ArrayList<>();
101-
102-
private boolean serializeNulls = DEFAULT_SERIALIZE_NULLS;
103-
private String datePattern = DEFAULT_DATE_PATTERN;
104-
private int dateStyle = DateFormat.DEFAULT;
105-
private int timeStyle = DateFormat.DEFAULT;
106-
private boolean complexMapKeySerialization = DEFAULT_COMPLEX_MAP_KEYS;
107-
private boolean serializeSpecialFloatingPointValues = DEFAULT_SPECIALIZE_FLOAT_VALUES;
108-
private boolean escapeHtmlChars = DEFAULT_ESCAPE_HTML;
109-
private FormattingStyle formattingStyle = DEFAULT_FORMATTING_STYLE;
110-
private boolean generateNonExecutableJson = DEFAULT_JSON_NON_EXECUTABLE;
111-
private Strictness strictness = DEFAULT_STRICTNESS;
112-
private boolean useJdkUnsafe = DEFAULT_USE_JDK_UNSAFE;
113-
private ToNumberStrategy objectToNumberStrategy = DEFAULT_OBJECT_TO_NUMBER_STRATEGY;
114-
private ToNumberStrategy numberToNumberStrategy = DEFAULT_NUMBER_TO_NUMBER_STRATEGY;
115-
private final ArrayDeque<ReflectionAccessFilter> reflectionFilters = new ArrayDeque<>();
135+
final List<TypeAdapterFactory> hierarchyFactories = new ArrayList<>();
136+
137+
boolean serializeNulls = DEFAULT_SERIALIZE_NULLS;
138+
String datePattern = DEFAULT_DATE_PATTERN;
139+
int dateStyle = DateFormat.DEFAULT;
140+
int timeStyle = DateFormat.DEFAULT;
141+
boolean complexMapKeySerialization = DEFAULT_COMPLEX_MAP_KEYS;
142+
boolean serializeSpecialFloatingPointValues = DEFAULT_SPECIALIZE_FLOAT_VALUES;
143+
boolean escapeHtmlChars = DEFAULT_ESCAPE_HTML;
144+
FormattingStyle formattingStyle = DEFAULT_FORMATTING_STYLE;
145+
boolean generateNonExecutableJson = DEFAULT_JSON_NON_EXECUTABLE;
146+
Strictness strictness = DEFAULT_STRICTNESS;
147+
boolean useJdkUnsafe = DEFAULT_USE_JDK_UNSAFE;
148+
ToNumberStrategy objectToNumberStrategy = DEFAULT_OBJECT_TO_NUMBER_STRATEGY;
149+
ToNumberStrategy numberToNumberStrategy = DEFAULT_NUMBER_TO_NUMBER_STRATEGY;
150+
final ArrayDeque<ReflectionAccessFilter> reflectionFilters = new ArrayDeque<>();
116151

117152
/**
118153
* Creates a GsonBuilder instance that can be used to build Gson with various configuration
@@ -884,43 +919,123 @@ public GsonBuilder addReflectionAccessFilter(ReflectionAccessFilter filter) {
884919
* @return an instance of Gson configured with the options currently set in this builder
885920
*/
886921
public Gson create() {
887-
List<TypeAdapterFactory> factories =
888-
new ArrayList<>(this.factories.size() + this.hierarchyFactories.size() + 3);
889-
factories.addAll(this.factories);
890-
Collections.reverse(factories);
891-
892-
List<TypeAdapterFactory> hierarchyFactories = new ArrayList<>(this.hierarchyFactories);
893-
Collections.reverse(hierarchyFactories);
894-
factories.addAll(hierarchyFactories);
895-
896-
addTypeAdaptersForDate(datePattern, dateStyle, timeStyle, factories);
897-
898-
return new Gson(
899-
excluder,
900-
fieldNamingPolicy,
901-
new HashMap<>(instanceCreators),
902-
serializeNulls,
903-
complexMapKeySerialization,
904-
generateNonExecutableJson,
905-
escapeHtmlChars,
906-
formattingStyle,
907-
strictness,
908-
serializeSpecialFloatingPointValues,
909-
useJdkUnsafe,
910-
longSerializationPolicy,
911-
datePattern,
912-
dateStyle,
913-
timeStyle,
914-
new ArrayList<>(this.factories),
915-
new ArrayList<>(this.hierarchyFactories),
916-
factories,
917-
objectToNumberStrategy,
918-
numberToNumberStrategy,
919-
new ArrayList<>(reflectionFilters));
920-
}
921-
922-
private static void addTypeAdaptersForDate(
923-
String datePattern, int dateStyle, int timeStyle, List<TypeAdapterFactory> factories) {
922+
return new Gson(this);
923+
}
924+
925+
List<TypeAdapterFactory> createFactories(
926+
ConstructorConstructor constructorConstructor,
927+
JsonAdapterAnnotationTypeAdapterFactory jsonAdapterFactory) {
928+
ArrayList<TypeAdapterFactory> factories = new ArrayList<>();
929+
930+
// built-in type adapters that cannot be overridden
931+
factories.add(TypeAdapters.JSON_ELEMENT_FACTORY);
932+
factories.add(ObjectTypeAdapter.getFactory(objectToNumberStrategy));
933+
934+
// the excluder must precede all adapters that handle user-defined types
935+
factories.add(excluder);
936+
937+
// users' type adapters
938+
addUserDefinedAdapters(factories);
939+
940+
// custom Date adapters
941+
addDateTypeAdapters(factories);
942+
943+
// type adapters for basic platform types
944+
factories.add(TypeAdapters.STRING_FACTORY);
945+
factories.add(TypeAdapters.INTEGER_FACTORY);
946+
factories.add(TypeAdapters.BOOLEAN_FACTORY);
947+
factories.add(TypeAdapters.BYTE_FACTORY);
948+
factories.add(TypeAdapters.SHORT_FACTORY);
949+
TypeAdapter<Number> longAdapter = longSerializationPolicy.typeAdapter();
950+
factories.add(TypeAdapters.newFactory(long.class, Long.class, longAdapter));
951+
factories.add(TypeAdapters.newFactory(double.class, Double.class, doubleAdapter()));
952+
factories.add(TypeAdapters.newFactory(float.class, Float.class, floatAdapter()));
953+
factories.add(NumberTypeAdapter.getFactory(numberToNumberStrategy));
954+
factories.add(TypeAdapters.ATOMIC_INTEGER_FACTORY);
955+
factories.add(TypeAdapters.ATOMIC_BOOLEAN_FACTORY);
956+
factories.add(
957+
TypeAdapters.newFactory(AtomicLong.class, TypeAdapters.atomicLongAdapter(longAdapter)));
958+
factories.add(
959+
TypeAdapters.newFactory(
960+
AtomicLongArray.class, TypeAdapters.atomicLongArrayAdapter(longAdapter)));
961+
factories.add(TypeAdapters.ATOMIC_INTEGER_ARRAY_FACTORY);
962+
factories.add(TypeAdapters.CHARACTER_FACTORY);
963+
factories.add(TypeAdapters.STRING_BUILDER_FACTORY);
964+
factories.add(TypeAdapters.STRING_BUFFER_FACTORY);
965+
factories.add(TypeAdapters.BIG_DECIMAL_FACTORY);
966+
factories.add(TypeAdapters.BIG_INTEGER_FACTORY);
967+
// Add adapter for LazilyParsedNumber because user can obtain it from Gson and then try to
968+
// serialize it again
969+
factories.add(TypeAdapters.LAZILY_PARSED_NUMBER_FACTORY);
970+
factories.add(TypeAdapters.URL_FACTORY);
971+
factories.add(TypeAdapters.URI_FACTORY);
972+
factories.add(TypeAdapters.UUID_FACTORY);
973+
factories.add(TypeAdapters.CURRENCY_FACTORY);
974+
factories.add(TypeAdapters.LOCALE_FACTORY);
975+
factories.add(TypeAdapters.INET_ADDRESS_FACTORY);
976+
factories.add(TypeAdapters.BIT_SET_FACTORY);
977+
factories.add(DefaultDateTypeAdapter.DEFAULT_STYLE_FACTORY);
978+
factories.add(TypeAdapters.CALENDAR_FACTORY);
979+
factories.addAll(SqlTypesSupport.SQL_TYPE_FACTORIES);
980+
factories.add(ArrayTypeAdapter.FACTORY);
981+
factories.add(TypeAdapters.CLASS_FACTORY);
982+
983+
// type adapters for composite and user-defined types
984+
factories.add(new CollectionTypeAdapterFactory(constructorConstructor));
985+
factories.add(new MapTypeAdapterFactory(constructorConstructor, complexMapKeySerialization));
986+
factories.add(jsonAdapterFactory);
987+
factories.add(TypeAdapters.ENUM_FACTORY);
988+
factories.add(
989+
new ReflectiveTypeAdapterFactory(
990+
constructorConstructor,
991+
fieldNamingPolicy,
992+
excluder,
993+
jsonAdapterFactory,
994+
newImmutableList(reflectionFilters)));
995+
996+
factories.trimToSize();
997+
return Collections.unmodifiableList(factories);
998+
}
999+
1000+
static <E> List<E> newImmutableList(Collection<E> collection) {
1001+
if (collection.isEmpty()) {
1002+
return Collections.emptyList();
1003+
}
1004+
if (collection.size() == 1) {
1005+
return Collections.singletonList(
1006+
collection instanceof List
1007+
? ((List<E>) collection).get(0)
1008+
: collection.iterator().next());
1009+
}
1010+
@SuppressWarnings("unchecked")
1011+
List<E> list = (List<E>) Collections.unmodifiableList(Arrays.asList(collection.toArray()));
1012+
return list;
1013+
}
1014+
1015+
private TypeAdapter<Number> doubleAdapter() {
1016+
return serializeSpecialFloatingPointValues ? TypeAdapters.DOUBLE : TypeAdapters.DOUBLE_STRICT;
1017+
}
1018+
1019+
private TypeAdapter<Number> floatAdapter() {
1020+
return serializeSpecialFloatingPointValues ? TypeAdapters.FLOAT : TypeAdapters.FLOAT_STRICT;
1021+
}
1022+
1023+
private void addUserDefinedAdapters(List<TypeAdapterFactory> all) {
1024+
if (!this.factories.isEmpty()) {
1025+
List<TypeAdapterFactory> reversedFactories = new ArrayList<>(this.factories);
1026+
Collections.reverse(reversedFactories);
1027+
all.addAll(reversedFactories);
1028+
}
1029+
1030+
if (!this.hierarchyFactories.isEmpty()) {
1031+
List<TypeAdapterFactory> reversedHierarchyFactories =
1032+
new ArrayList<>(this.hierarchyFactories);
1033+
Collections.reverse(reversedHierarchyFactories);
1034+
all.addAll(reversedHierarchyFactories);
1035+
}
1036+
}
1037+
1038+
private void addDateTypeAdapters(List<TypeAdapterFactory> factories) {
9241039
TypeAdapterFactory dateAdapterFactory;
9251040
boolean sqlTypesSupported = SqlTypesSupport.SUPPORTS_SQL_TYPES;
9261041
TypeAdapterFactory sqlTimestampAdapterFactory = null;

gson/src/main/java/com/google/gson/LongSerializationPolicy.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package com.google.gson;
1818

19+
import com.google.gson.internal.bind.TypeAdapters;
20+
1921
/**
2022
* Defines the expected format for a {@code long} or {@code Long} type when it is serialized.
2123
*
@@ -39,6 +41,11 @@ public JsonElement serialize(Long value) {
3941
}
4042
return new JsonPrimitive(value);
4143
}
44+
45+
@Override
46+
TypeAdapter<Number> typeAdapter() {
47+
return TypeAdapters.LONG;
48+
}
4249
},
4350

4451
/**
@@ -55,6 +62,11 @@ public JsonElement serialize(Long value) {
5562
}
5663
return new JsonPrimitive(value.toString());
5764
}
65+
66+
@Override
67+
TypeAdapter<Number> typeAdapter() {
68+
return TypeAdapters.LONG_AS_STRING;
69+
}
5870
};
5971

6072
/**
@@ -64,4 +76,8 @@ public JsonElement serialize(Long value) {
6476
* @return the serialized version of {@code value}
6577
*/
6678
public abstract JsonElement serialize(Long value);
79+
80+
/** Returns the corresponding {@link TypeAdapter} for this serialization policy. */
81+
// Internal method
82+
abstract TypeAdapter<Number> typeAdapter();
6783
}

gson/src/main/java/com/google/gson/internal/ConstructorConstructor.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import java.util.ArrayDeque;
3131
import java.util.ArrayList;
3232
import java.util.Collection;
33+
import java.util.Collections;
3334
import java.util.EnumMap;
3435
import java.util.EnumSet;
3536
import java.util.LinkedHashMap;
@@ -43,6 +44,11 @@
4344

4445
/** Returns a function that can construct an instance of a requested type. */
4546
public final class ConstructorConstructor {
47+
public static final boolean DEFAULT_USE_JDK_UNSAFE = true;
48+
public static final ConstructorConstructor DEFAULT =
49+
new ConstructorConstructor(
50+
Collections.emptyMap(), DEFAULT_USE_JDK_UNSAFE, Collections.emptyList());
51+
4652
private final Map<Type, InstanceCreator<?>> instanceCreators;
4753
private final boolean useJdkUnsafe;
4854
private final List<ReflectionAccessFilter> reflectionFilters;

gson/src/main/java/com/google/gson/internal/bind/EnumTypeAdapter.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
5050
}
5151
};
5252

53-
private final Map<String, T> nameToConstant = new HashMap<>();
54-
private final Map<String, T> stringToConstant = new HashMap<>();
55-
private final Map<T, String> constantToName = new HashMap<>();
53+
private final Map<String, T> nameToConstant;
54+
private final Map<String, T> stringToConstant;
55+
private final Map<T, String> constantToName;
5656

5757
private EnumTypeAdapter(Class<T> classOfT) {
5858
try {
@@ -73,6 +73,11 @@ private EnumTypeAdapter(Class<T> classOfT) {
7373

7474
AccessibleObject.setAccessible(fields, true);
7575

76+
nameToConstant = new HashMap<>(constantCount);
77+
stringToConstant = new HashMap<>(constantCount);
78+
// Don't use `EnumMap` here; that can break when using ProGuard or R8
79+
constantToName = new HashMap<>(constantCount);
80+
7681
for (Field constantField : fields) {
7782
@SuppressWarnings("unchecked")
7883
T constant = (T) constantField.get(null);

0 commit comments

Comments
 (0)