• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.gson;
18 
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_JSON_NON_EXECUTABLE;
23 import static com.google.gson.Gson.DEFAULT_LENIENT;
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_PRETTY_PRINT;
27 import static com.google.gson.Gson.DEFAULT_SERIALIZE_NULLS;
28 import static com.google.gson.Gson.DEFAULT_SPECIALIZE_FLOAT_VALUES;
29 import static com.google.gson.Gson.DEFAULT_USE_JDK_UNSAFE;
30 
31 import com.google.gson.annotations.Since;
32 import com.google.gson.annotations.Until;
33 import com.google.gson.internal.$Gson$Preconditions;
34 import com.google.gson.internal.Excluder;
35 import com.google.gson.internal.bind.DefaultDateTypeAdapter;
36 import com.google.gson.internal.bind.TreeTypeAdapter;
37 import com.google.gson.internal.bind.TypeAdapters;
38 import com.google.gson.internal.sql.SqlTypesSupport;
39 import com.google.gson.reflect.TypeToken;
40 import com.google.gson.stream.JsonReader;
41 import com.google.gson.stream.JsonWriter;
42 import java.lang.reflect.Type;
43 import java.text.DateFormat;
44 import java.util.ArrayList;
45 import java.util.Collections;
46 import java.util.Date;
47 import java.util.HashMap;
48 import java.util.LinkedList;
49 import java.util.List;
50 import java.util.Map;
51 import java.util.Objects;
52 
53 /**
54  * <p>Use this builder to construct a {@link Gson} instance when you need to set configuration
55  * options other than the default. For {@link Gson} with default configuration, it is simpler to
56  * use {@code new Gson()}. {@code GsonBuilder} is best used by creating it, and then invoking its
57  * various configuration methods, and finally calling create.</p>
58  *
59  * <p>The following is an example shows how to use the {@code GsonBuilder} to construct a Gson
60  * instance:
61  *
62  * <pre>
63  * Gson gson = new GsonBuilder()
64  *     .registerTypeAdapter(Id.class, new IdTypeAdapter())
65  *     .enableComplexMapKeySerialization()
66  *     .serializeNulls()
67  *     .setDateFormat(DateFormat.LONG)
68  *     .setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)
69  *     .setPrettyPrinting()
70  *     .setVersion(1.0)
71  *     .create();
72  * </pre>
73  *
74  * <p>NOTES:
75  * <ul>
76  * <li> the order of invocation of configuration methods does not matter.</li>
77  * <li> The default serialization of {@link Date} and its subclasses in Gson does
78  *  not contain time-zone information. So, if you are using date/time instances,
79  *  use {@code GsonBuilder} and its {@code setDateFormat} methods.</li>
80  * </ul>
81  *
82  * @author Inderjeet Singh
83  * @author Joel Leitch
84  * @author Jesse Wilson
85  */
86 public final class GsonBuilder {
87   private Excluder excluder = Excluder.DEFAULT;
88   private LongSerializationPolicy longSerializationPolicy = LongSerializationPolicy.DEFAULT;
89   private FieldNamingStrategy fieldNamingPolicy = FieldNamingPolicy.IDENTITY;
90   private final Map<Type, InstanceCreator<?>> instanceCreators = new HashMap<>();
91   private final List<TypeAdapterFactory> factories = new ArrayList<>();
92   /** tree-style hierarchy factories. These come after factories for backwards compatibility. */
93   private final List<TypeAdapterFactory> hierarchyFactories = new ArrayList<>();
94   private boolean serializeNulls = DEFAULT_SERIALIZE_NULLS;
95   private String datePattern = DEFAULT_DATE_PATTERN;
96   private int dateStyle = DateFormat.DEFAULT;
97   private int timeStyle = DateFormat.DEFAULT;
98   private boolean complexMapKeySerialization = DEFAULT_COMPLEX_MAP_KEYS;
99   private boolean serializeSpecialFloatingPointValues = DEFAULT_SPECIALIZE_FLOAT_VALUES;
100   private boolean escapeHtmlChars = DEFAULT_ESCAPE_HTML;
101   private boolean prettyPrinting = DEFAULT_PRETTY_PRINT;
102   private boolean generateNonExecutableJson = DEFAULT_JSON_NON_EXECUTABLE;
103   private boolean lenient = DEFAULT_LENIENT;
104   private boolean useJdkUnsafe = DEFAULT_USE_JDK_UNSAFE;
105   private ToNumberStrategy objectToNumberStrategy = DEFAULT_OBJECT_TO_NUMBER_STRATEGY;
106   private ToNumberStrategy numberToNumberStrategy = DEFAULT_NUMBER_TO_NUMBER_STRATEGY;
107   private final LinkedList<ReflectionAccessFilter> reflectionFilters = new LinkedList<>();
108 
109   /**
110    * Creates a GsonBuilder instance that can be used to build Gson with various configuration
111    * settings. GsonBuilder follows the builder pattern, and it is typically used by first
112    * invoking various configuration methods to set desired options, and finally calling
113    * {@link #create()}.
114    */
GsonBuilder()115   public GsonBuilder() {
116   }
117 
118   /**
119    * Constructs a GsonBuilder instance from a Gson instance. The newly constructed GsonBuilder
120    * has the same configuration as the previously built Gson instance.
121    *
122    * @param gson the gson instance whose configuration should by applied to a new GsonBuilder.
123    */
GsonBuilder(Gson gson)124   GsonBuilder(Gson gson) {
125     this.excluder = gson.excluder;
126     this.fieldNamingPolicy = gson.fieldNamingStrategy;
127     this.instanceCreators.putAll(gson.instanceCreators);
128     this.serializeNulls = gson.serializeNulls;
129     this.complexMapKeySerialization = gson.complexMapKeySerialization;
130     this.generateNonExecutableJson = gson.generateNonExecutableJson;
131     this.escapeHtmlChars = gson.htmlSafe;
132     this.prettyPrinting = gson.prettyPrinting;
133     this.lenient = gson.lenient;
134     this.serializeSpecialFloatingPointValues = gson.serializeSpecialFloatingPointValues;
135     this.longSerializationPolicy = gson.longSerializationPolicy;
136     this.datePattern = gson.datePattern;
137     this.dateStyle = gson.dateStyle;
138     this.timeStyle = gson.timeStyle;
139     this.factories.addAll(gson.builderFactories);
140     this.hierarchyFactories.addAll(gson.builderHierarchyFactories);
141     this.useJdkUnsafe = gson.useJdkUnsafe;
142     this.objectToNumberStrategy = gson.objectToNumberStrategy;
143     this.numberToNumberStrategy = gson.numberToNumberStrategy;
144     this.reflectionFilters.addAll(gson.reflectionFilters);
145   }
146 
147   /**
148    * Configures Gson to enable versioning support. Versioning support works based on the
149    * annotation types {@link Since} and {@link Until}. It allows including or excluding fields
150    * and classes based on the specified version. See the documentation of these annotation
151    * types for more information.
152    *
153    * <p>By default versioning support is disabled and usage of {@code @Since} and {@code @Until}
154    * has no effect.
155    *
156    * @param version the version number to use.
157    * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
158    * @throws IllegalArgumentException if the version number is NaN or negative
159    * @see Since
160    * @see Until
161    */
setVersion(double version)162   public GsonBuilder setVersion(double version) {
163     if (Double.isNaN(version) || version < 0.0) {
164       throw new IllegalArgumentException("Invalid version: " + version);
165     }
166     excluder = excluder.withVersion(version);
167     return this;
168   }
169 
170   /**
171    * Configures Gson to excludes all class fields that have the specified modifiers. By default,
172    * Gson will exclude all fields marked {@code transient} or {@code static}. This method will
173    * override that behavior.
174    *
175    * <p>This is a convenience method which behaves as if an {@link ExclusionStrategy} which
176    * excludes these fields was {@linkplain #setExclusionStrategies(ExclusionStrategy...) registered with this builder}.
177    *
178    * @param modifiers the field modifiers. You must use the modifiers specified in the
179    * {@link java.lang.reflect.Modifier} class. For example,
180    * {@link java.lang.reflect.Modifier#TRANSIENT},
181    * {@link java.lang.reflect.Modifier#STATIC}.
182    * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
183    */
excludeFieldsWithModifiers(int... modifiers)184   public GsonBuilder excludeFieldsWithModifiers(int... modifiers) {
185     Objects.requireNonNull(modifiers);
186     excluder = excluder.withModifiers(modifiers);
187     return this;
188   }
189 
190   /**
191    * Makes the output JSON non-executable in Javascript by prefixing the generated JSON with some
192    * special text. This prevents attacks from third-party sites through script sourcing. See
193    * <a href="http://code.google.com/p/google-gson/issues/detail?id=42">Gson Issue 42</a>
194    * for details.
195    *
196    * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
197    * @since 1.3
198    */
generateNonExecutableJson()199   public GsonBuilder generateNonExecutableJson() {
200     this.generateNonExecutableJson = true;
201     return this;
202   }
203 
204   /**
205    * Configures Gson to exclude all fields from consideration for serialization and deserialization
206    * that do not have the {@link com.google.gson.annotations.Expose} annotation.
207    *
208    * <p>This is a convenience method which behaves as if an {@link ExclusionStrategy} which excludes
209    * these fields was {@linkplain #setExclusionStrategies(ExclusionStrategy...) registered with this builder}.
210    *
211    * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
212    */
excludeFieldsWithoutExposeAnnotation()213   public GsonBuilder excludeFieldsWithoutExposeAnnotation() {
214     excluder = excluder.excludeFieldsWithoutExposeAnnotation();
215     return this;
216   }
217 
218   /**
219    * Configure Gson to serialize null fields. By default, Gson omits all fields that are null
220    * during serialization.
221    *
222    * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
223    * @since 1.2
224    */
serializeNulls()225   public GsonBuilder serializeNulls() {
226     this.serializeNulls = true;
227     return this;
228   }
229 
230   /**
231    * Enabling this feature will only change the serialized form if the map key is
232    * a complex type (i.e. non-primitive) in its <strong>serialized</strong> JSON
233    * form. The default implementation of map serialization uses {@code toString()}
234    * on the key; however, when this is called then one of the following cases
235    * apply:
236    *
237    * <p><b>Maps as JSON objects</b>
238    *
239    * <p>For this case, assume that a type adapter is registered to serialize and
240    * deserialize some {@code Point} class, which contains an x and y coordinate,
241    * to/from the JSON Primitive string value {@code "(x,y)"}. The Java map would
242    * then be serialized as a {@link JsonObject}.
243    *
244    * <p>Below is an example:
245    * <pre>  {@code
246    *   Gson gson = new GsonBuilder()
247    *       .register(Point.class, new MyPointTypeAdapter())
248    *       .enableComplexMapKeySerialization()
249    *       .create();
250    *
251    *   Map<Point, String> original = new LinkedHashMap<>();
252    *   original.put(new Point(5, 6), "a");
253    *   original.put(new Point(8, 8), "b");
254    *   System.out.println(gson.toJson(original, type));
255    * }</pre>
256    * The above code prints this JSON object:<pre>  {@code
257    *   {
258    *     "(5,6)": "a",
259    *     "(8,8)": "b"
260    *   }
261    * }</pre>
262    *
263    * <p><b>Maps as JSON arrays</b>
264    *
265    * <p>For this case, assume that a type adapter was NOT registered for some
266    * {@code Point} class, but rather the default Gson serialization is applied.
267    * In this case, some {@code new Point(2,3)} would serialize as {@code
268    * {"x":2,"y":3}}.
269    *
270    * <p>Given the assumption above, a {@code Map<Point, String>} will be
271    * serialize as an array of arrays (can be viewed as an entry set of pairs).
272    *
273    * <p>Below is an example of serializing complex types as JSON arrays:
274    * <pre> {@code
275    *   Gson gson = new GsonBuilder()
276    *       .enableComplexMapKeySerialization()
277    *       .create();
278    *
279    *   Map<Point, String> original = new LinkedHashMap<>();
280    *   original.put(new Point(5, 6), "a");
281    *   original.put(new Point(8, 8), "b");
282    *   System.out.println(gson.toJson(original, type));
283    * }
284    * </pre>
285    *
286    * The JSON output would look as follows:
287    * <pre>   {@code
288    *   [
289    *     [
290    *       {
291    *         "x": 5,
292    *         "y": 6
293    *       },
294    *       "a"
295    *     ],
296    *     [
297    *       {
298    *         "x": 8,
299    *         "y": 8
300    *       },
301    *       "b"
302    *     ]
303    *   ]
304    * }</pre>
305    *
306    * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
307    * @since 1.7
308    */
enableComplexMapKeySerialization()309   public GsonBuilder enableComplexMapKeySerialization() {
310     complexMapKeySerialization = true;
311     return this;
312   }
313 
314   /**
315    * Configures Gson to exclude inner classes (= non-{@code static} nested classes) during serialization
316    * and deserialization. This is a convenience method which behaves as if an {@link ExclusionStrategy}
317    * which excludes inner classes was {@linkplain #setExclusionStrategies(ExclusionStrategy...) registered with this builder}.
318    * This means inner classes will be serialized as JSON {@code null}, and will be deserialized as
319    * Java {@code null} with their JSON data being ignored. And fields with an inner class as type will
320    * be ignored during serialization and deserialization.
321    *
322    * <p>By default Gson serializes and deserializes inner classes, but ignores references to the
323    * enclosing instance. Deserialization might not be possible at all when {@link #disableJdkUnsafe()}
324    * is used (and no custom {@link InstanceCreator} is registered), or it can lead to unexpected
325    * {@code NullPointerException}s when the deserialized instance is used afterwards.
326    *
327    * <p>In general using inner classes with Gson should be avoided; they should be converted to {@code static}
328    * nested classes if possible.
329    *
330    * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
331    * @since 1.3
332    */
disableInnerClassSerialization()333   public GsonBuilder disableInnerClassSerialization() {
334     excluder = excluder.disableInnerClassSerialization();
335     return this;
336   }
337 
338   /**
339    * Configures Gson to apply a specific serialization policy for {@code Long} and {@code long}
340    * objects.
341    *
342    * @param serializationPolicy the particular policy to use for serializing longs.
343    * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
344    * @since 1.3
345    */
setLongSerializationPolicy(LongSerializationPolicy serializationPolicy)346   public GsonBuilder setLongSerializationPolicy(LongSerializationPolicy serializationPolicy) {
347     this.longSerializationPolicy = Objects.requireNonNull(serializationPolicy);
348     return this;
349   }
350 
351   /**
352    * Configures Gson to apply a specific naming policy to an object's fields during serialization
353    * and deserialization.
354    *
355    * <p>This method just delegates to {@link #setFieldNamingStrategy(FieldNamingStrategy)}.
356    */
setFieldNamingPolicy(FieldNamingPolicy namingConvention)357   public GsonBuilder setFieldNamingPolicy(FieldNamingPolicy namingConvention) {
358     return setFieldNamingStrategy(namingConvention);
359   }
360 
361   /**
362    * Configures Gson to apply a specific naming strategy to an object's fields during
363    * serialization and deserialization.
364    *
365    * <p>The created Gson instance might only use the field naming strategy once for a
366    * field and cache the result. It is not guaranteed that the strategy will be used
367    * again every time the value of a field is serialized or deserialized.
368    *
369    * @param fieldNamingStrategy the naming strategy to apply to the fields
370    * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
371    * @since 1.3
372    */
setFieldNamingStrategy(FieldNamingStrategy fieldNamingStrategy)373   public GsonBuilder setFieldNamingStrategy(FieldNamingStrategy fieldNamingStrategy) {
374     this.fieldNamingPolicy = Objects.requireNonNull(fieldNamingStrategy);
375     return this;
376   }
377 
378   /**
379    * Configures Gson to apply a specific number strategy during deserialization of {@link Object}.
380    *
381    * @param objectToNumberStrategy the actual object-to-number strategy
382    * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
383    * @see ToNumberPolicy#DOUBLE The default object-to-number strategy
384    * @since 2.8.9
385    */
setObjectToNumberStrategy(ToNumberStrategy objectToNumberStrategy)386   public GsonBuilder setObjectToNumberStrategy(ToNumberStrategy objectToNumberStrategy) {
387     this.objectToNumberStrategy = Objects.requireNonNull(objectToNumberStrategy);
388     return this;
389   }
390 
391   /**
392    * Configures Gson to apply a specific number strategy during deserialization of {@link Number}.
393    *
394    * @param numberToNumberStrategy the actual number-to-number strategy
395    * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
396    * @see ToNumberPolicy#LAZILY_PARSED_NUMBER The default number-to-number strategy
397    * @since 2.8.9
398    */
setNumberToNumberStrategy(ToNumberStrategy numberToNumberStrategy)399   public GsonBuilder setNumberToNumberStrategy(ToNumberStrategy numberToNumberStrategy) {
400     this.numberToNumberStrategy = Objects.requireNonNull(numberToNumberStrategy);
401     return this;
402   }
403 
404   /**
405    * Configures Gson to apply a set of exclusion strategies during both serialization and
406    * deserialization. Each of the {@code strategies} will be applied as a disjunction rule.
407    * This means that if one of the {@code strategies} suggests that a field (or class) should be
408    * skipped then that field (or object) is skipped during serialization/deserialization.
409    * The strategies are added to the existing strategies (if any); the existing strategies
410    * are not replaced.
411    *
412    * <p>Fields are excluded for serialization and deserialization when
413    * {@link ExclusionStrategy#shouldSkipField(FieldAttributes) shouldSkipField} returns {@code true},
414    * or when {@link ExclusionStrategy#shouldSkipClass(Class) shouldSkipClass} returns {@code true}
415    * for the field type. Gson behaves as if the field did not exist; its value is not serialized
416    * and on deserialization if a JSON member with this name exists it is skipped by default.<br>
417    * When objects of an excluded type (as determined by
418    * {@link ExclusionStrategy#shouldSkipClass(Class) shouldSkipClass}) are serialized a
419    * JSON null is written to output, and when deserialized the JSON value is skipped and
420    * {@code null} is returned.
421    *
422    * <p>The created Gson instance might only use an exclusion strategy once for a field or
423    * class and cache the result. It is not guaranteed that the strategy will be used again
424    * every time the value of a field or a class is serialized or deserialized.
425    *
426    * @param strategies the set of strategy object to apply during object (de)serialization.
427    * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
428    * @since 1.4
429    */
setExclusionStrategies(ExclusionStrategy... strategies)430   public GsonBuilder setExclusionStrategies(ExclusionStrategy... strategies) {
431     Objects.requireNonNull(strategies);
432     for (ExclusionStrategy strategy : strategies) {
433       excluder = excluder.withExclusionStrategy(strategy, true, true);
434     }
435     return this;
436   }
437 
438   /**
439    * Configures Gson to apply the passed in exclusion strategy during serialization.
440    * If this method is invoked numerous times with different exclusion strategy objects
441    * then the exclusion strategies that were added will be applied as a disjunction rule.
442    * This means that if one of the added exclusion strategies suggests that a field (or
443    * class) should be skipped then that field (or object) is skipped during its
444    * serialization.
445    *
446    * <p>See the documentation of {@link #setExclusionStrategies(ExclusionStrategy...)}
447    * for a detailed description of the effect of exclusion strategies.
448    *
449    * @param strategy an exclusion strategy to apply during serialization.
450    * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
451    * @since 1.7
452    */
addSerializationExclusionStrategy(ExclusionStrategy strategy)453   public GsonBuilder addSerializationExclusionStrategy(ExclusionStrategy strategy) {
454     Objects.requireNonNull(strategy);
455     excluder = excluder.withExclusionStrategy(strategy, true, false);
456     return this;
457   }
458 
459   /**
460    * Configures Gson to apply the passed in exclusion strategy during deserialization.
461    * If this method is invoked numerous times with different exclusion strategy objects
462    * then the exclusion strategies that were added will be applied as a disjunction rule.
463    * This means that if one of the added exclusion strategies suggests that a field (or
464    * class) should be skipped then that field (or object) is skipped during its
465    * deserialization.
466    *
467    * <p>See the documentation of {@link #setExclusionStrategies(ExclusionStrategy...)}
468    * for a detailed description of the effect of exclusion strategies.
469    *
470    * @param strategy an exclusion strategy to apply during deserialization.
471    * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
472    * @since 1.7
473    */
addDeserializationExclusionStrategy(ExclusionStrategy strategy)474   public GsonBuilder addDeserializationExclusionStrategy(ExclusionStrategy strategy) {
475     Objects.requireNonNull(strategy);
476     excluder = excluder.withExclusionStrategy(strategy, false, true);
477     return this;
478   }
479 
480   /**
481    * Configures Gson to output Json that fits in a page for pretty printing. This option only
482    * affects Json serialization.
483    *
484    * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
485    */
setPrettyPrinting()486   public GsonBuilder setPrettyPrinting() {
487     prettyPrinting = true;
488     return this;
489   }
490 
491   /**
492    * Configures Gson to allow JSON data which does not strictly comply with the JSON specification.
493    *
494    * <p>Note: Due to legacy reasons most methods of Gson are always lenient, regardless of
495    * whether this builder method is used.
496    *
497    * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
498    * @see JsonReader#setLenient(boolean)
499    * @see JsonWriter#setLenient(boolean)
500    */
setLenient()501   public GsonBuilder setLenient() {
502     lenient = true;
503     return this;
504   }
505 
506   /**
507    * By default, Gson escapes HTML characters such as &lt; &gt; etc. Use this option to configure
508    * Gson to pass-through HTML characters as is.
509    *
510    * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
511    * @since 1.3
512    */
disableHtmlEscaping()513   public GsonBuilder disableHtmlEscaping() {
514     this.escapeHtmlChars = false;
515     return this;
516   }
517 
518   /**
519    * Configures Gson to serialize {@code Date} objects according to the pattern provided. You can
520    * call this method or {@link #setDateFormat(int)} multiple times, but only the last invocation
521    * will be used to decide the serialization format.
522    *
523    * <p>The date format will be used to serialize and deserialize {@link java.util.Date} and in case
524    * the {@code java.sql} module is present, also {@link java.sql.Timestamp} and {@link java.sql.Date}.
525    *
526    * <p>Note that this pattern must abide by the convention provided by {@code SimpleDateFormat}
527    * class. See the documentation in {@link java.text.SimpleDateFormat} for more information on
528    * valid date and time patterns.</p>
529    *
530    * @param pattern the pattern that dates will be serialized/deserialized to/from
531    * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
532    * @since 1.2
533    */
setDateFormat(String pattern)534   public GsonBuilder setDateFormat(String pattern) {
535     // TODO(Joel): Make this fail fast if it is an invalid date format
536     this.datePattern = pattern;
537     return this;
538   }
539 
540   /**
541    * Configures Gson to to serialize {@code Date} objects according to the style value provided.
542    * You can call this method or {@link #setDateFormat(String)} multiple times, but only the last
543    * invocation will be used to decide the serialization format.
544    *
545    * <p>Note that this style value should be one of the predefined constants in the
546    * {@code DateFormat} class. See the documentation in {@link java.text.DateFormat} for more
547    * information on the valid style constants.</p>
548    *
549    * @param style the predefined date style that date objects will be serialized/deserialized
550    * to/from
551    * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
552    * @since 1.2
553    */
setDateFormat(int style)554   public GsonBuilder setDateFormat(int style) {
555     this.dateStyle = style;
556     this.datePattern = null;
557     return this;
558   }
559 
560   /**
561    * Configures Gson to to serialize {@code Date} objects according to the style value provided.
562    * You can call this method or {@link #setDateFormat(String)} multiple times, but only the last
563    * invocation will be used to decide the serialization format.
564    *
565    * <p>Note that this style value should be one of the predefined constants in the
566    * {@code DateFormat} class. See the documentation in {@link java.text.DateFormat} for more
567    * information on the valid style constants.</p>
568    *
569    * @param dateStyle the predefined date style that date objects will be serialized/deserialized
570    * to/from
571    * @param timeStyle the predefined style for the time portion of the date objects
572    * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
573    * @since 1.2
574    */
setDateFormat(int dateStyle, int timeStyle)575   public GsonBuilder setDateFormat(int dateStyle, int timeStyle) {
576     this.dateStyle = dateStyle;
577     this.timeStyle = timeStyle;
578     this.datePattern = null;
579     return this;
580   }
581 
582   /**
583    * Configures Gson for custom serialization or deserialization. This method combines the
584    * registration of an {@link TypeAdapter}, {@link InstanceCreator}, {@link JsonSerializer}, and a
585    * {@link JsonDeserializer}. It is best used when a single object {@code typeAdapter} implements
586    * all the required interfaces for custom serialization with Gson. If a type adapter was
587    * previously registered for the specified {@code type}, it is overwritten.
588    *
589    * <p>This registers the type specified and no other types: you must manually register related
590    * types! For example, applications registering {@code boolean.class} should also register {@code
591    * Boolean.class}.
592    *
593    * <p>{@link JsonSerializer} and {@link JsonDeserializer} are made "{@code null}-safe". This
594    * means when trying to serialize {@code null}, Gson will write a JSON {@code null} and the
595    * serializer is not called. Similarly when deserializing a JSON {@code null}, Gson will emit
596    * {@code null} without calling the deserializer. If it is desired to handle {@code null} values,
597    * a {@link TypeAdapter} should be used instead.
598    *
599    * @param type the type definition for the type adapter being registered
600    * @param typeAdapter This object must implement at least one of the {@link TypeAdapter},
601    * {@link InstanceCreator}, {@link JsonSerializer}, and a {@link JsonDeserializer} interfaces.
602    * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
603    */
registerTypeAdapter(Type type, Object typeAdapter)604   public GsonBuilder registerTypeAdapter(Type type, Object typeAdapter) {
605     Objects.requireNonNull(type);
606     $Gson$Preconditions.checkArgument(typeAdapter instanceof JsonSerializer<?>
607         || typeAdapter instanceof JsonDeserializer<?>
608         || typeAdapter instanceof InstanceCreator<?>
609         || typeAdapter instanceof TypeAdapter<?>);
610     if (typeAdapter instanceof InstanceCreator<?>) {
611       instanceCreators.put(type, (InstanceCreator<?>) typeAdapter);
612     }
613     if (typeAdapter instanceof JsonSerializer<?> || typeAdapter instanceof JsonDeserializer<?>) {
614       TypeToken<?> typeToken = TypeToken.get(type);
615       factories.add(TreeTypeAdapter.newFactoryWithMatchRawType(typeToken, typeAdapter));
616     }
617     if (typeAdapter instanceof TypeAdapter<?>) {
618       @SuppressWarnings({"unchecked", "rawtypes"})
619       TypeAdapterFactory factory = TypeAdapters.newFactory(TypeToken.get(type), (TypeAdapter)typeAdapter);
620       factories.add(factory);
621     }
622     return this;
623   }
624 
625   /**
626    * Register a factory for type adapters. Registering a factory is useful when the type
627    * adapter needs to be configured based on the type of the field being processed. Gson
628    * is designed to handle a large number of factories, so you should consider registering
629    * them to be at par with registering an individual type adapter.
630    *
631    * <p>The created Gson instance might only use the factory once to create an adapter for
632    * a specific type and cache the result. It is not guaranteed that the factory will be used
633    * again every time the type is serialized or deserialized.
634    *
635    * @since 2.1
636    */
registerTypeAdapterFactory(TypeAdapterFactory factory)637   public GsonBuilder registerTypeAdapterFactory(TypeAdapterFactory factory) {
638     Objects.requireNonNull(factory);
639     factories.add(factory);
640     return this;
641   }
642 
643   /**
644    * Configures Gson for custom serialization or deserialization for an inheritance type hierarchy.
645    * This method combines the registration of a {@link TypeAdapter}, {@link JsonSerializer} and
646    * a {@link JsonDeserializer}. If a type adapter was previously registered for the specified
647    * type hierarchy, it is overridden. If a type adapter is registered for a specific type in
648    * the type hierarchy, it will be invoked instead of the one registered for the type hierarchy.
649    *
650    * @param baseType the class definition for the type adapter being registered for the base class
651    *        or interface
652    * @param typeAdapter This object must implement at least one of {@link TypeAdapter},
653    *        {@link JsonSerializer} or {@link JsonDeserializer} interfaces.
654    * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
655    * @since 1.7
656    */
registerTypeHierarchyAdapter(Class<?> baseType, Object typeAdapter)657   public GsonBuilder registerTypeHierarchyAdapter(Class<?> baseType, Object typeAdapter) {
658     Objects.requireNonNull(baseType);
659     $Gson$Preconditions.checkArgument(typeAdapter instanceof JsonSerializer<?>
660         || typeAdapter instanceof JsonDeserializer<?>
661         || typeAdapter instanceof TypeAdapter<?>);
662     if (typeAdapter instanceof JsonDeserializer || typeAdapter instanceof JsonSerializer) {
663       hierarchyFactories.add(TreeTypeAdapter.newTypeHierarchyFactory(baseType, typeAdapter));
664     }
665     if (typeAdapter instanceof TypeAdapter<?>) {
666       @SuppressWarnings({"unchecked", "rawtypes"})
667       TypeAdapterFactory factory = TypeAdapters.newTypeHierarchyFactory(baseType, (TypeAdapter)typeAdapter);
668       factories.add(factory);
669     }
670     return this;
671   }
672 
673   /**
674    * Section 2.4 of <a href="http://www.ietf.org/rfc/rfc4627.txt">JSON specification</a> disallows
675    * special double values (NaN, Infinity, -Infinity). However,
676    * <a href="http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf">Javascript
677    * specification</a> (see section 4.3.20, 4.3.22, 4.3.23) allows these values as valid Javascript
678    * values. Moreover, most JavaScript engines will accept these special values in JSON without
679    * problem. So, at a practical level, it makes sense to accept these values as valid JSON even
680    * though JSON specification disallows them.
681    *
682    * <p>Gson always accepts these special values during deserialization. However, it outputs
683    * strictly compliant JSON. Hence, if it encounters a float value {@link Float#NaN},
684    * {@link Float#POSITIVE_INFINITY}, {@link Float#NEGATIVE_INFINITY}, or a double value
685    * {@link Double#NaN}, {@link Double#POSITIVE_INFINITY}, {@link Double#NEGATIVE_INFINITY}, it
686    * will throw an {@link IllegalArgumentException}. This method provides a way to override the
687    * default behavior when you know that the JSON receiver will be able to handle these special
688    * values.
689    *
690    * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
691    * @since 1.3
692    */
serializeSpecialFloatingPointValues()693   public GsonBuilder serializeSpecialFloatingPointValues() {
694     this.serializeSpecialFloatingPointValues = true;
695     return this;
696   }
697 
698   /**
699    * Disables usage of JDK's {@code sun.misc.Unsafe}.
700    *
701    * <p>By default Gson uses {@code Unsafe} to create instances of classes which don't have
702    * a no-args constructor. However, {@code Unsafe} might not be available for all Java
703    * runtimes. For example Android does not provide {@code Unsafe}, or only with limited
704    * functionality. Additionally {@code Unsafe} creates instances without executing any
705    * constructor or initializer block, or performing initialization of field values. This can
706    * lead to surprising and difficult to debug errors.
707    * Therefore, to get reliable behavior regardless of which runtime is used, and to detect
708    * classes which cannot be deserialized in an early stage of development, this method allows
709    * disabling usage of {@code Unsafe}.
710    *
711    * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
712    * @since 2.9.0
713    */
disableJdkUnsafe()714   public GsonBuilder disableJdkUnsafe() {
715     this.useJdkUnsafe = false;
716     return this;
717   }
718 
719   /**
720    * Adds a reflection access filter. A reflection access filter prevents Gson from using
721    * reflection for the serialization and deserialization of certain classes. The logic in
722    * the filter specifies which classes those are.
723    *
724    * <p>Filters will be invoked in reverse registration order, that is, the most recently
725    * added filter will be invoked first.
726    *
727    * <p>By default Gson has no filters configured and will try to use reflection for
728    * all classes for which no {@link TypeAdapter} has been registered, and for which no
729    * built-in Gson {@code TypeAdapter} exists.
730    *
731    * <p>The created Gson instance might only use an access filter once for a class or its
732    * members and cache the result. It is not guaranteed that the filter will be used again
733    * every time a class or its members are accessed during serialization or deserialization.
734    *
735    * @param filter filter to add
736    * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
737    * @since 2.9.1
738    */
addReflectionAccessFilter(ReflectionAccessFilter filter)739   public GsonBuilder addReflectionAccessFilter(ReflectionAccessFilter filter) {
740     Objects.requireNonNull(filter);
741     reflectionFilters.addFirst(filter);
742     return this;
743   }
744 
745   /**
746    * Creates a {@link Gson} instance based on the current configuration. This method is free of
747    * side-effects to this {@code GsonBuilder} instance and hence can be called multiple times.
748    *
749    * @return an instance of Gson configured with the options currently set in this builder
750    */
create()751   public Gson create() {
752     List<TypeAdapterFactory> factories = new ArrayList<>(this.factories.size() + this.hierarchyFactories.size() + 3);
753     factories.addAll(this.factories);
754     Collections.reverse(factories);
755 
756     List<TypeAdapterFactory> hierarchyFactories = new ArrayList<>(this.hierarchyFactories);
757     Collections.reverse(hierarchyFactories);
758     factories.addAll(hierarchyFactories);
759 
760     addTypeAdaptersForDate(datePattern, dateStyle, timeStyle, factories);
761 
762     return new Gson(excluder, fieldNamingPolicy, new HashMap<>(instanceCreators),
763         serializeNulls, complexMapKeySerialization,
764         generateNonExecutableJson, escapeHtmlChars, prettyPrinting, lenient,
765         serializeSpecialFloatingPointValues, useJdkUnsafe, longSerializationPolicy,
766         datePattern, dateStyle, timeStyle, new ArrayList<>(this.factories),
767         new ArrayList<>(this.hierarchyFactories), factories,
768         objectToNumberStrategy, numberToNumberStrategy, new ArrayList<>(reflectionFilters));
769   }
770 
addTypeAdaptersForDate(String datePattern, int dateStyle, int timeStyle, List<TypeAdapterFactory> factories)771   private void addTypeAdaptersForDate(String datePattern, int dateStyle, int timeStyle,
772       List<TypeAdapterFactory> factories) {
773     TypeAdapterFactory dateAdapterFactory;
774     boolean sqlTypesSupported = SqlTypesSupport.SUPPORTS_SQL_TYPES;
775     TypeAdapterFactory sqlTimestampAdapterFactory = null;
776     TypeAdapterFactory sqlDateAdapterFactory = null;
777 
778     if (datePattern != null && !datePattern.trim().isEmpty()) {
779       dateAdapterFactory = DefaultDateTypeAdapter.DateType.DATE.createAdapterFactory(datePattern);
780 
781       if (sqlTypesSupported) {
782         sqlTimestampAdapterFactory = SqlTypesSupport.TIMESTAMP_DATE_TYPE.createAdapterFactory(datePattern);
783         sqlDateAdapterFactory = SqlTypesSupport.DATE_DATE_TYPE.createAdapterFactory(datePattern);
784       }
785     } else if (dateStyle != DateFormat.DEFAULT && timeStyle != DateFormat.DEFAULT) {
786       dateAdapterFactory = DefaultDateTypeAdapter.DateType.DATE.createAdapterFactory(dateStyle, timeStyle);
787 
788       if (sqlTypesSupported) {
789         sqlTimestampAdapterFactory = SqlTypesSupport.TIMESTAMP_DATE_TYPE.createAdapterFactory(dateStyle, timeStyle);
790         sqlDateAdapterFactory = SqlTypesSupport.DATE_DATE_TYPE.createAdapterFactory(dateStyle, timeStyle);
791       }
792     } else {
793       return;
794     }
795 
796     factories.add(dateAdapterFactory);
797     if (sqlTypesSupported) {
798       factories.add(sqlTimestampAdapterFactory);
799       factories.add(sqlDateAdapterFactory);
800     }
801   }
802 }
803