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 java.lang.reflect.Type;
20 import java.sql.Timestamp;
21 import java.text.DateFormat;
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.Date;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28
29 import com.google.gson.internal.$Gson$Preconditions;
30 import com.google.gson.internal.Excluder;
31 import com.google.gson.internal.bind.TreeTypeAdapter;
32 import com.google.gson.internal.bind.TypeAdapters;
33 import com.google.gson.reflect.TypeToken;
34 import com.google.gson.stream.JsonReader;
35
36 import static com.google.gson.Gson.DEFAULT_COMPLEX_MAP_KEYS;
37 import static com.google.gson.Gson.DEFAULT_ESCAPE_HTML;
38 import static com.google.gson.Gson.DEFAULT_JSON_NON_EXECUTABLE;
39 import static com.google.gson.Gson.DEFAULT_LENIENT;
40 import static com.google.gson.Gson.DEFAULT_PRETTY_PRINT;
41 import static com.google.gson.Gson.DEFAULT_SERIALIZE_NULLS;
42 import static com.google.gson.Gson.DEFAULT_SPECIALIZE_FLOAT_VALUES;
43
44 /**
45 * <p>Use this builder to construct a {@link Gson} instance when you need to set configuration
46 * options other than the default. For {@link Gson} with default configuration, it is simpler to
47 * use {@code new Gson()}. {@code GsonBuilder} is best used by creating it, and then invoking its
48 * various configuration methods, and finally calling create.</p>
49 *
50 * <p>The following is an example shows how to use the {@code GsonBuilder} to construct a Gson
51 * instance:
52 *
53 * <pre>
54 * Gson gson = new GsonBuilder()
55 * .registerTypeAdapter(Id.class, new IdTypeAdapter())
56 * .enableComplexMapKeySerialization()
57 * .serializeNulls()
58 * .setDateFormat(DateFormat.LONG)
59 * .setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)
60 * .setPrettyPrinting()
61 * .setVersion(1.0)
62 * .create();
63 * </pre></p>
64 *
65 * <p>NOTES:
66 * <ul>
67 * <li> the order of invocation of configuration methods does not matter.</li>
68 * <li> The default serialization of {@link Date} and its subclasses in Gson does
69 * not contain time-zone information. So, if you are using date/time instances,
70 * use {@code GsonBuilder} and its {@code setDateFormat} methods.</li>
71 * </ul>
72 * </p>
73 *
74 * @author Inderjeet Singh
75 * @author Joel Leitch
76 * @author Jesse Wilson
77 */
78 public final class GsonBuilder {
79 private Excluder excluder = Excluder.DEFAULT;
80 private LongSerializationPolicy longSerializationPolicy = LongSerializationPolicy.DEFAULT;
81 private FieldNamingStrategy fieldNamingPolicy = FieldNamingPolicy.IDENTITY;
82 private final Map<Type, InstanceCreator<?>> instanceCreators
83 = new HashMap<Type, InstanceCreator<?>>();
84 private final List<TypeAdapterFactory> factories = new ArrayList<TypeAdapterFactory>();
85 /** tree-style hierarchy factories. These come after factories for backwards compatibility. */
86 private final List<TypeAdapterFactory> hierarchyFactories = new ArrayList<TypeAdapterFactory>();
87 private boolean serializeNulls = DEFAULT_SERIALIZE_NULLS;
88 private String datePattern;
89 private int dateStyle = DateFormat.DEFAULT;
90 private int timeStyle = DateFormat.DEFAULT;
91 private boolean complexMapKeySerialization = DEFAULT_COMPLEX_MAP_KEYS;
92 private boolean serializeSpecialFloatingPointValues = DEFAULT_SPECIALIZE_FLOAT_VALUES;
93 private boolean escapeHtmlChars = DEFAULT_ESCAPE_HTML;
94 private boolean prettyPrinting = DEFAULT_PRETTY_PRINT;
95 private boolean generateNonExecutableJson = DEFAULT_JSON_NON_EXECUTABLE;
96 private boolean lenient = DEFAULT_LENIENT;
97
98 /**
99 * Creates a GsonBuilder instance that can be used to build Gson with various configuration
100 * settings. GsonBuilder follows the builder pattern, and it is typically used by first
101 * invoking various configuration methods to set desired options, and finally calling
102 * {@link #create()}.
103 */
104 public GsonBuilder() {
105 }
106
107 /**
108 * Constructs a GsonBuilder instance from a Gson instance. The newly constructed GsonBuilder
109 * has the same configuration as the previously built Gson instance.
110 *
111 * @param gson the gson instance whose configuration should by applied to a new GsonBuilder.
112 */
113 GsonBuilder(Gson gson) {
114 this.excluder = gson.excluder;
115 this.fieldNamingPolicy = gson.fieldNamingStrategy;
116 this.instanceCreators.putAll(gson.instanceCreators);
117 this.serializeNulls = gson.serializeNulls;
118 this.complexMapKeySerialization = gson.complexMapKeySerialization;
119 this.generateNonExecutableJson = gson.generateNonExecutableJson;
120 this.escapeHtmlChars = gson.htmlSafe;
121 this.prettyPrinting = gson.prettyPrinting;
122 this.lenient = gson.lenient;
123 this.serializeSpecialFloatingPointValues = gson.serializeSpecialFloatingPointValues;
124 this.longSerializationPolicy = gson.longSerializationPolicy;
125 this.datePattern = gson.datePattern;
126 this.dateStyle = gson.dateStyle;
127 this.timeStyle = gson.timeStyle;
128 this.factories.addAll(gson.builderFactories);
129 this.hierarchyFactories.addAll(gson.builderHierarchyFactories);
130 }
131
132 /**
133 * Configures Gson to enable versioning support.
134 *
135 * @param ignoreVersionsAfter any field or type marked with a version higher than this value
136 * are ignored during serialization or deserialization.
137 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
138 */
139 public GsonBuilder setVersion(double ignoreVersionsAfter) {
140 excluder = excluder.withVersion(ignoreVersionsAfter);
141 return this;
142 }
143
144 /**
145 * Configures Gson to excludes all class fields that have the specified modifiers. By default,
146 * Gson will exclude all fields marked transient or static. This method will override that
147 * behavior.
148 *
149 * @param modifiers the field modifiers. You must use the modifiers specified in the
150 * {@link java.lang.reflect.Modifier} class. For example,
151 * {@link java.lang.reflect.Modifier#TRANSIENT},
152 * {@link java.lang.reflect.Modifier#STATIC}.
153 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
154 */
155 public GsonBuilder excludeFieldsWithModifiers(int... modifiers) {
156 excluder = excluder.withModifiers(modifiers);
157 return this;
158 }
159
160 /**
161 * Makes the output JSON non-executable in Javascript by prefixing the generated JSON with some
162 * special text. This prevents attacks from third-party sites through script sourcing. See
163 * <a href="http://code.google.com/p/google-gson/issues/detail?id=42">Gson Issue 42</a>
164 * for details.
165 *
166 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
167 * @since 1.3
168 */
169 public GsonBuilder generateNonExecutableJson() {
170 this.generateNonExecutableJson = true;
171 return this;
172 }
173
174 /**
175 * Configures Gson to exclude all fields from consideration for serialization or deserialization
176 * that do not have the {@link com.google.gson.annotations.Expose} annotation.
177 *
178 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
179 */
180 public GsonBuilder excludeFieldsWithoutExposeAnnotation() {
181 excluder = excluder.excludeFieldsWithoutExposeAnnotation();
182 return this;
183 }
184
185 /**
186 * Configure Gson to serialize null fields. By default, Gson omits all fields that are null
187 * during serialization.
188 *
189 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
190 * @since 1.2
191 */
192 public GsonBuilder serializeNulls() {
193 this.serializeNulls = true;
194 return this;
195 }
196
197 /**
198 * Enabling this feature will only change the serialized form if the map key is
199 * a complex type (i.e. non-primitive) in its <strong>serialized</strong> JSON
200 * form. The default implementation of map serialization uses {@code toString()}
201 * on the key; however, when this is called then one of the following cases
202 * apply:
203 *
204 * <h3>Maps as JSON objects</h3>
205 * For this case, assume that a type adapter is registered to serialize and
206 * deserialize some {@code Point} class, which contains an x and y coordinate,
207 * to/from the JSON Primitive string value {@code "(x,y)"}. The Java map would
208 * then be serialized as a {@link JsonObject}.
209 *
210 * <p>Below is an example:
211 * <pre> {@code
212 * Gson gson = new GsonBuilder()
213 * .register(Point.class, new MyPointTypeAdapter())
214 * .enableComplexMapKeySerialization()
215 * .create();
216 *
217 * Map<Point, String> original = new LinkedHashMap<Point, String>();
218 * original.put(new Point(5, 6), "a");
219 * original.put(new Point(8, 8), "b");
220 * System.out.println(gson.toJson(original, type));
221 * }</pre>
222 * The above code prints this JSON object:<pre> {@code
223 * {
224 * "(5,6)": "a",
225 * "(8,8)": "b"
226 * }
227 * }</pre>
228 *
229 * <h3>Maps as JSON arrays</h3>
230 * For this case, assume that a type adapter was NOT registered for some
231 * {@code Point} class, but rather the default Gson serialization is applied.
232 * In this case, some {@code new Point(2,3)} would serialize as {@code
233 * {"x":2,"y":5}}.
234 *
235 * <p>Given the assumption above, a {@code Map<Point, String>} will be
236 * serialize as an array of arrays (can be viewed as an entry set of pairs).
237 *
238 * <p>Below is an example of serializing complex types as JSON arrays:
239 * <pre> {@code
240 * Gson gson = new GsonBuilder()
241 * .enableComplexMapKeySerialization()
242 * .create();
243 *
244 * Map<Point, String> original = new LinkedHashMap<Point, String>();
245 * original.put(new Point(5, 6), "a");
246 * original.put(new Point(8, 8), "b");
247 * System.out.println(gson.toJson(original, type));
248 * }
249 *
250 * The JSON output would look as follows:
251 * <pre> {@code
252 * [
253 * [
254 * {
255 * "x": 5,
256 * "y": 6
257 * },
258 * "a"
259 * ],
260 * [
261 * {
262 * "x": 8,
263 * "y": 8
264 * },
265 * "b"
266 * ]
267 * ]
268 * }</pre>
269 *
270 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
271 * @since 1.7
272 */
273 public GsonBuilder enableComplexMapKeySerialization() {
274 complexMapKeySerialization = true;
275 return this;
276 }
277
278 /**
279 * Configures Gson to exclude inner classes during serialization.
280 *
281 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
282 * @since 1.3
283 */
284 public GsonBuilder disableInnerClassSerialization() {
285 excluder = excluder.disableInnerClassSerialization();
286 return this;
287 }
288
289 /**
290 * Configures Gson to apply a specific serialization policy for {@code Long} and {@code long}
291 * objects.
292 *
293 * @param serializationPolicy the particular policy to use for serializing longs.
294 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
295 * @since 1.3
296 */
297 public GsonBuilder setLongSerializationPolicy(LongSerializationPolicy serializationPolicy) {
298 this.longSerializationPolicy = serializationPolicy;
299 return this;
300 }
301
302 /**
303 * Configures Gson to apply a specific naming policy to an object's field during serialization
304 * and deserialization.
305 *
306 * @param namingConvention the JSON field naming convention to use for serialization and
307 * deserialization.
308 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
309 */
310 public GsonBuilder setFieldNamingPolicy(FieldNamingPolicy namingConvention) {
311 this.fieldNamingPolicy = namingConvention;
312 return this;
313 }
314
315 /**
316 * Configures Gson to apply a specific naming policy strategy to an object's field during
317 * serialization and deserialization.
318 *
319 * @param fieldNamingStrategy the actual naming strategy to apply to the fields
320 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
321 * @since 1.3
322 */
323 public GsonBuilder setFieldNamingStrategy(FieldNamingStrategy fieldNamingStrategy) {
324 this.fieldNamingPolicy = fieldNamingStrategy;
325 return this;
326 }
327
328 /**
329 * Configures Gson to apply a set of exclusion strategies during both serialization and
330 * deserialization. Each of the {@code strategies} will be applied as a disjunction rule.
331 * This means that if one of the {@code strategies} suggests that a field (or class) should be
332 * skipped then that field (or object) is skipped during serialization/deserialization.
333 *
334 * @param strategies the set of strategy object to apply during object (de)serialization.
335 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
336 * @since 1.4
337 */
338 public GsonBuilder setExclusionStrategies(ExclusionStrategy... strategies) {
339 for (ExclusionStrategy strategy : strategies) {
340 excluder = excluder.withExclusionStrategy(strategy, true, true);
341 }
342 return this;
343 }
344
345 /**
346 * Configures Gson to apply the passed in exclusion strategy during serialization.
347 * If this method is invoked numerous times with different exclusion strategy objects
348 * then the exclusion strategies that were added will be applied as a disjunction rule.
349 * This means that if one of the added exclusion strategies suggests that a field (or
350 * class) should be skipped then that field (or object) is skipped during its
351 * serialization.
352 *
353 * @param strategy an exclusion strategy to apply during serialization.
354 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
355 * @since 1.7
356 */
357 public GsonBuilder addSerializationExclusionStrategy(ExclusionStrategy strategy) {
358 excluder = excluder.withExclusionStrategy(strategy, true, false);
359 return this;
360 }
361
362 /**
363 * Configures Gson to apply the passed in exclusion strategy during deserialization.
364 * If this method is invoked numerous times with different exclusion strategy objects
365 * then the exclusion strategies that were added will be applied as a disjunction rule.
366 * This means that if one of the added exclusion strategies suggests that a field (or
367 * class) should be skipped then that field (or object) is skipped during its
368 * deserialization.
369 *
370 * @param strategy an exclusion strategy to apply during deserialization.
371 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
372 * @since 1.7
373 */
374 public GsonBuilder addDeserializationExclusionStrategy(ExclusionStrategy strategy) {
375 excluder = excluder.withExclusionStrategy(strategy, false, true);
376 return this;
377 }
378
379 /**
380 * Configures Gson to output Json that fits in a page for pretty printing. This option only
381 * affects Json serialization.
382 *
383 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
384 */
385 public GsonBuilder setPrettyPrinting() {
386 prettyPrinting = true;
387 return this;
388 }
389
390 /**
391 * By default, Gson is strict and only accepts JSON as specified by
392 * <a href="http://www.ietf.org/rfc/rfc4627.txt">RFC 4627</a>. This option makes the parser
393 * liberal in what it accepts.
394 *
395 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
396 * @see JsonReader#setLenient(boolean)
397 */
398 public GsonBuilder setLenient() {
399 lenient = true;
400 return this;
401 }
402
403 /**
404 * By default, Gson escapes HTML characters such as < > etc. Use this option to configure
405 * Gson to pass-through HTML characters as is.
406 *
407 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
408 * @since 1.3
409 */
410 public GsonBuilder disableHtmlEscaping() {
411 this.escapeHtmlChars = false;
412 return this;
413 }
414
415 /**
416 * Configures Gson to serialize {@code Date} objects according to the pattern provided. You can
417 * call this method or {@link #setDateFormat(int)} multiple times, but only the last invocation
418 * will be used to decide the serialization format.
419 *
420 * <p>The date format will be used to serialize and deserialize {@link java.util.Date}, {@link
421 * java.sql.Timestamp} and {@link java.sql.Date}.
422 *
423 * <p>Note that this pattern must abide by the convention provided by {@code SimpleDateFormat}
424 * class. See the documentation in {@link java.text.SimpleDateFormat} for more information on
425 * valid date and time patterns.</p>
426 *
427 * @param pattern the pattern that dates will be serialized/deserialized to/from
428 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
429 * @since 1.2
430 */
431 public GsonBuilder setDateFormat(String pattern) {
432 // TODO(Joel): Make this fail fast if it is an invalid date format
433 this.datePattern = pattern;
434 return this;
435 }
436
437 /**
438 * Configures Gson to to serialize {@code Date} objects according to the style value provided.
439 * You can call this method or {@link #setDateFormat(String)} multiple times, but only the last
440 * invocation will be used to decide the serialization format.
441 *
442 * <p>Note that this style value should be one of the predefined constants in the
443 * {@code DateFormat} class. See the documentation in {@link java.text.DateFormat} for more
444 * information on the valid style constants.</p>
445 *
446 * @param style the predefined date style that date objects will be serialized/deserialized
447 * to/from
448 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
449 * @since 1.2
450 */
451 public GsonBuilder setDateFormat(int style) {
452 this.dateStyle = style;
453 this.datePattern = null;
454 return this;
455 }
456
457 /**
458 * Configures Gson to to serialize {@code Date} objects according to the style value provided.
459 * You can call this method or {@link #setDateFormat(String)} multiple times, but only the last
460 * invocation will be used to decide the serialization format.
461 *
462 * <p>Note that this style value should be one of the predefined constants in the
463 * {@code DateFormat} class. See the documentation in {@link java.text.DateFormat} for more
464 * information on the valid style constants.</p>
465 *
466 * @param dateStyle the predefined date style that date objects will be serialized/deserialized
467 * to/from
468 * @param timeStyle the predefined style for the time portion of the date objects
469 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
470 * @since 1.2
471 */
472 public GsonBuilder setDateFormat(int dateStyle, int timeStyle) {
473 this.dateStyle = dateStyle;
474 this.timeStyle = timeStyle;
475 this.datePattern = null;
476 return this;
477 }
478
479 /**
480 * Configures Gson for custom serialization or deserialization. This method combines the
481 * registration of an {@link TypeAdapter}, {@link InstanceCreator}, {@link JsonSerializer}, and a
482 * {@link JsonDeserializer}. It is best used when a single object {@code typeAdapter} implements
483 * all the required interfaces for custom serialization with Gson. If a type adapter was
484 * previously registered for the specified {@code type}, it is overwritten.
485 *
486 * <p>This registers the type specified and no other types: you must manually register related
487 * types! For example, applications registering {@code boolean.class} should also register {@code
488 * Boolean.class}.
489 *
490 * @param type the type definition for the type adapter being registered
491 * @param typeAdapter This object must implement at least one of the {@link TypeAdapter},
492 * {@link InstanceCreator}, {@link JsonSerializer}, and a {@link JsonDeserializer} interfaces.
493 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
494 */
495 @SuppressWarnings({"unchecked", "rawtypes"})
496 public GsonBuilder registerTypeAdapter(Type type, Object typeAdapter) {
497 $Gson$Preconditions.checkArgument(typeAdapter instanceof JsonSerializer<?>
498 || typeAdapter instanceof JsonDeserializer<?>
499 || typeAdapter instanceof InstanceCreator<?>
500 || typeAdapter instanceof TypeAdapter<?>);
501 if (typeAdapter instanceof InstanceCreator<?>) {
502 instanceCreators.put(type, (InstanceCreator) typeAdapter);
503 }
504 if (typeAdapter instanceof JsonSerializer<?> || typeAdapter instanceof JsonDeserializer<?>) {
505 TypeToken<?> typeToken = TypeToken.get(type);
506 factories.add(TreeTypeAdapter.newFactoryWithMatchRawType(typeToken, typeAdapter));
507 }
508 if (typeAdapter instanceof TypeAdapter<?>) {
509 factories.add(TypeAdapters.newFactory(TypeToken.get(type), (TypeAdapter)typeAdapter));
510 }
511 return this;
512 }
513
514 /**
515 * Register a factory for type adapters. Registering a factory is useful when the type
516 * adapter needs to be configured based on the type of the field being processed. Gson
517 * is designed to handle a large number of factories, so you should consider registering
518 * them to be at par with registering an individual type adapter.
519 *
520 * @since 2.1
521 */
522 public GsonBuilder registerTypeAdapterFactory(TypeAdapterFactory factory) {
523 factories.add(factory);
524 return this;
525 }
526
527 /**
528 * Configures Gson for custom serialization or deserialization for an inheritance type hierarchy.
529 * This method combines the registration of a {@link TypeAdapter}, {@link JsonSerializer} and
530 * a {@link JsonDeserializer}. If a type adapter was previously registered for the specified
531 * type hierarchy, it is overridden. If a type adapter is registered for a specific type in
532 * the type hierarchy, it will be invoked instead of the one registered for the type hierarchy.
533 *
534 * @param baseType the class definition for the type adapter being registered for the base class
535 * or interface
536 * @param typeAdapter This object must implement at least one of {@link TypeAdapter},
537 * {@link JsonSerializer} or {@link JsonDeserializer} interfaces.
538 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
539 * @since 1.7
540 */
541 @SuppressWarnings({"unchecked", "rawtypes"})
542 public GsonBuilder registerTypeHierarchyAdapter(Class<?> baseType, Object typeAdapter) {
543 $Gson$Preconditions.checkArgument(typeAdapter instanceof JsonSerializer<?>
544 || typeAdapter instanceof JsonDeserializer<?>
545 || typeAdapter instanceof TypeAdapter<?>);
546 if (typeAdapter instanceof JsonDeserializer || typeAdapter instanceof JsonSerializer) {
547 hierarchyFactories.add(TreeTypeAdapter.newTypeHierarchyFactory(baseType, typeAdapter));
548 }
549 if (typeAdapter instanceof TypeAdapter<?>) {
550 factories.add(TypeAdapters.newTypeHierarchyFactory(baseType, (TypeAdapter)typeAdapter));
551 }
552 return this;
553 }
554
555 /**
556 * Section 2.4 of <a href="http://www.ietf.org/rfc/rfc4627.txt">JSON specification</a> disallows
557 * special double values (NaN, Infinity, -Infinity). However,
558 * <a href="http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf">Javascript
559 * specification</a> (see section 4.3.20, 4.3.22, 4.3.23) allows these values as valid Javascript
560 * values. Moreover, most JavaScript engines will accept these special values in JSON without
561 * problem. So, at a practical level, it makes sense to accept these values as valid JSON even
562 * though JSON specification disallows them.
563 *
564 * <p>Gson always accepts these special values during deserialization. However, it outputs
565 * strictly compliant JSON. Hence, if it encounters a float value {@link Float#NaN},
566 * {@link Float#POSITIVE_INFINITY}, {@link Float#NEGATIVE_INFINITY}, or a double value
567 * {@link Double#NaN}, {@link Double#POSITIVE_INFINITY}, {@link Double#NEGATIVE_INFINITY}, it
568 * will throw an {@link IllegalArgumentException}. This method provides a way to override the
569 * default behavior when you know that the JSON receiver will be able to handle these special
570 * values.
571 *
572 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
573 * @since 1.3
574 */
575 public GsonBuilder serializeSpecialFloatingPointValues() {
576 this.serializeSpecialFloatingPointValues = true;
577 return this;
578 }
579
580 /**
581 * Creates a {@link Gson} instance based on the current configuration. This method is free of
582 * side-effects to this {@code GsonBuilder} instance and hence can be called multiple times.
583 *
584 * @return an instance of Gson configured with the options currently set in this builder
585 */
586 public Gson create() {
587 List<TypeAdapterFactory> factories = new ArrayList<TypeAdapterFactory>(this.factories.size() + this.hierarchyFactories.size() + 3);
588 factories.addAll(this.factories);
589 Collections.reverse(factories);
590
591 List<TypeAdapterFactory> hierarchyFactories = new ArrayList<TypeAdapterFactory>(this.hierarchyFactories);
592 Collections.reverse(hierarchyFactories);
593 factories.addAll(hierarchyFactories);
594
595 addTypeAdaptersForDate(datePattern, dateStyle, timeStyle, factories);
596
597 return new Gson(excluder, fieldNamingPolicy, instanceCreators,
598 serializeNulls, complexMapKeySerialization,
599 generateNonExecutableJson, escapeHtmlChars, prettyPrinting, lenient,
600 serializeSpecialFloatingPointValues, longSerializationPolicy,
601 datePattern, dateStyle, timeStyle,
602 this.factories, this.hierarchyFactories, factories);
603 }
604
605 @SuppressWarnings("unchecked")
606 private void addTypeAdaptersForDate(String datePattern, int dateStyle, int timeStyle,
607 List<TypeAdapterFactory> factories) {
608 DefaultDateTypeAdapter dateTypeAdapter;
609 TypeAdapter<Timestamp> timestampTypeAdapter;
610 TypeAdapter<java.sql.Date> javaSqlDateTypeAdapter;
611 if (datePattern != null && !"".equals(datePattern.trim())) {
612 dateTypeAdapter = new DefaultDateTypeAdapter(Date.class, datePattern);
613 timestampTypeAdapter = (TypeAdapter) new DefaultDateTypeAdapter(Timestamp.class, datePattern);
614 javaSqlDateTypeAdapter = (TypeAdapter) new DefaultDateTypeAdapter(java.sql.Date.class, datePattern);
615 } else if (dateStyle != DateFormat.DEFAULT && timeStyle != DateFormat.DEFAULT) {
616 dateTypeAdapter = new DefaultDateTypeAdapter(Date.class, dateStyle, timeStyle);
617 timestampTypeAdapter = (TypeAdapter) new DefaultDateTypeAdapter(Timestamp.class, dateStyle, timeStyle);
618 javaSqlDateTypeAdapter = (TypeAdapter) new DefaultDateTypeAdapter(java.sql.Date.class, dateStyle, timeStyle);
619 } else {
620 return;
621 }
622
623 factories.add(TypeAdapters.newFactory(Date.class, dateTypeAdapter));
624 factories.add(TypeAdapters.newFactory(Timestamp.class, timestampTypeAdapter));
625 factories.add(TypeAdapters.newFactory(java.sql.Date.class, javaSqlDateTypeAdapter));
626 }
627 }
628