2 * Copyright (C) 2008 Google Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com
.google
.gson
;
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
;
29 import com
.google
.gson
.internal
.$Gson$Preconditions
;
30 import com
.google
.gson
.internal
.Excluder
;
31 import com
.google
.gson
.internal
.bind
.TypeAdapters
;
32 import com
.google
.gson
.reflect
.TypeToken
;
35 * <p>Use this builder to construct a {@link Gson} instance when you need to set configuration
36 * options other than the default. For {@link Gson} with default configuration, it is simpler to
37 * use {@code new Gson()}. {@code GsonBuilder} is best used by creating it, and then invoking its
38 * various configuration methods, and finally calling create.</p>
40 * <p>The following is an example shows how to use the {@code GsonBuilder} to construct a Gson
44 * Gson gson = new GsonBuilder()
45 * .registerTypeAdapter(Id.class, new IdTypeAdapter())
46 * .enableComplexMapKeySerialization()
48 * .setDateFormat(DateFormat.LONG)
49 * .setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)
50 * .setPrettyPrinting()
57 * <li> the order of invocation of configuration methods does not matter.</li>
58 * <li> The default serialization of {@link Date} and its subclasses in Gson does
59 * not contain time-zone information. So, if you are using date/time instances,
60 * use {@code GsonBuilder} and its {@code setDateFormat} methods.</li>
64 * @author Inderjeet Singh
66 * @author Jesse Wilson
68 public final class GsonBuilder
{
69 private Excluder excluder
= Excluder
.DEFAULT
;
70 private LongSerializationPolicy longSerializationPolicy
= LongSerializationPolicy
.DEFAULT
;
71 private FieldNamingStrategy fieldNamingPolicy
= FieldNamingPolicy
.IDENTITY
;
72 private final Map
<Type
, InstanceCreator
<?
>> instanceCreators
73 = new HashMap
<Type
, InstanceCreator
<?
>>();
74 private final List
<TypeAdapterFactory
> factories
= new ArrayList
<TypeAdapterFactory
>();
75 /** tree-style hierarchy factories. These come after factories for backwards compatibility. */
76 private final List
<TypeAdapterFactory
> hierarchyFactories
= new ArrayList
<TypeAdapterFactory
>();
77 private boolean serializeNulls
;
78 private String datePattern
;
79 private int dateStyle
= DateFormat
.DEFAULT
;
80 private int timeStyle
= DateFormat
.DEFAULT
;
81 private boolean complexMapKeySerialization
;
82 private boolean serializeSpecialFloatingPointValues
;
83 private boolean escapeHtmlChars
= true;
84 private boolean prettyPrinting
;
85 private boolean generateNonExecutableJson
;
88 * Creates a GsonBuilder instance that can be used to build Gson with various configuration
89 * settings. GsonBuilder follows the builder pattern, and it is typically used by first
90 * invoking various configuration methods to set desired options, and finally calling
93 public GsonBuilder() {
97 * Configures Gson to enable versioning support.
99 * @param ignoreVersionsAfter any field or type marked with a version higher than this value
100 * are ignored during serialization or deserialization.
101 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
103 public GsonBuilder
setVersion(double ignoreVersionsAfter
) {
104 excluder
= excluder
.withVersion(ignoreVersionsAfter
);
109 * Configures Gson to excludes all class fields that have the specified modifiers. By default,
110 * Gson will exclude all fields marked transient or static. This method will override that
113 * @param modifiers the field modifiers. You must use the modifiers specified in the
114 * {@link java.lang.reflect.Modifier} class. For example,
115 * {@link java.lang.reflect.Modifier#TRANSIENT},
116 * {@link java.lang.reflect.Modifier#STATIC}.
117 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
119 public GsonBuilder
excludeFieldsWithModifiers(int... modifiers
) {
120 excluder
= excluder
.withModifiers(modifiers
);
125 * Makes the output JSON non-executable in Javascript by prefixing the generated JSON with some
126 * special text. This prevents attacks from third-party sites through script sourcing. See
127 * <a href="http://code.google.com/p/google-gson/issues/detail?id=42">Gson Issue 42</a>
130 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
133 public GsonBuilder
generateNonExecutableJson() {
134 this.generateNonExecutableJson
= true;
139 * Configures Gson to exclude all fields from consideration for serialization or deserialization
140 * that do not have the {@link com.google.gson.annotations.Expose} annotation.
142 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
144 public GsonBuilder
excludeFieldsWithoutExposeAnnotation() {
145 excluder
= excluder
.excludeFieldsWithoutExposeAnnotation();
150 * Configure Gson to serialize null fields. By default, Gson omits all fields that are null
151 * during serialization.
153 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
156 public GsonBuilder
serializeNulls() {
157 this.serializeNulls
= true;
162 * Enabling this feature will only change the serialized form if the map key is
163 * a complex type (i.e. non-primitive) in its <strong>serialized</strong> JSON
164 * form. The default implementation of map serialization uses {@code toString()}
165 * on the key; however, when this is called then one of the following cases
168 * <h3>Maps as JSON objects</h3>
169 * For this case, assume that a type adapter is registered to serialize and
170 * deserialize some {@code Point} class, which contains an x and y coordinate,
171 * to/from the JSON Primitive string value {@code "(x,y)"}. The Java map would
172 * then be serialized as a {@link JsonObject}.
174 * <p>Below is an example:
176 * Gson gson = new GsonBuilder()
177 * .register(Point.class, new MyPointTypeAdapter())
178 * .enableComplexMapKeySerialization()
181 * Map<Point, String> original = new LinkedHashMap<Point, String>();
182 * original.put(new Point(5, 6), "a");
183 * original.put(new Point(8, 8), "b");
184 * System.out.println(gson.toJson(original, type));
186 * The above code prints this JSON object:<pre> {@code
193 * <h3>Maps as JSON arrays</h3>
194 * For this case, assume that a type adapter was NOT registered for some
195 * {@code Point} class, but rather the default Gson serialization is applied.
196 * In this case, some {@code new Point(2,3)} would serialize as {@code
199 * <p>Given the assumption above, a {@code Map<Point, String>} will be
200 * serialize as an array of arrays (can be viewed as an entry set of pairs).
202 * <p>Below is an example of serializing complex types as JSON arrays:
204 * Gson gson = new GsonBuilder()
205 * .enableComplexMapKeySerialization()
208 * Map<Point, String> original = new LinkedHashMap<Point, String>();
209 * original.put(new Point(5, 6), "a");
210 * original.put(new Point(8, 8), "b");
211 * System.out.println(gson.toJson(original, type));
214 * The JSON output would look as follows:
234 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
237 public GsonBuilder
enableComplexMapKeySerialization() {
238 complexMapKeySerialization
= true;
243 * Configures Gson to exclude inner classes during serialization.
245 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
248 public GsonBuilder
disableInnerClassSerialization() {
249 excluder
= excluder
.disableInnerClassSerialization();
254 * Configures Gson to apply a specific serialization policy for {@code Long} and {@code long}
257 * @param serializationPolicy the particular policy to use for serializing longs.
258 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
261 public GsonBuilder
setLongSerializationPolicy(LongSerializationPolicy serializationPolicy
) {
262 this.longSerializationPolicy
= serializationPolicy
;
267 * Configures Gson to apply a specific naming policy to an object's field during serialization
268 * and deserialization.
270 * @param namingConvention the JSON field naming convention to use for serialization and
272 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
274 public GsonBuilder
setFieldNamingPolicy(FieldNamingPolicy namingConvention
) {
275 this.fieldNamingPolicy
= namingConvention
;
280 * Configures Gson to apply a specific naming policy strategy to an object's field during
281 * serialization and deserialization.
283 * @param fieldNamingStrategy the actual naming strategy to apply to the fields
284 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
287 public GsonBuilder
setFieldNamingStrategy(FieldNamingStrategy fieldNamingStrategy
) {
288 this.fieldNamingPolicy
= fieldNamingStrategy
;
293 * Configures Gson to apply a set of exclusion strategies during both serialization and
294 * deserialization. Each of the {@code strategies} will be applied as a disjunction rule.
295 * This means that if one of the {@code strategies} suggests that a field (or class) should be
296 * skipped then that field (or object) is skipped during serializaiton/deserialization.
298 * @param strategies the set of strategy object to apply during object (de)serialization.
299 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
302 public GsonBuilder
setExclusionStrategies(ExclusionStrategy
... strategies
) {
303 for (ExclusionStrategy strategy
: strategies
) {
304 excluder
= excluder
.withExclusionStrategy(strategy
, true, true);
310 * Configures Gson to apply the passed in exclusion strategy during serialization.
311 * If this method is invoked numerous times with different exclusion strategy objects
312 * then the exclusion strategies that were added will be applied as a disjunction rule.
313 * This means that if one of the added exclusion strategies suggests that a field (or
314 * class) should be skipped then that field (or object) is skipped during its
317 * @param strategy an exclusion strategy to apply during serialization.
318 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
321 public GsonBuilder
addSerializationExclusionStrategy(ExclusionStrategy strategy
) {
322 excluder
= excluder
.withExclusionStrategy(strategy
, true, false);
327 * Configures Gson to apply the passed in exclusion strategy during deserialization.
328 * If this method is invoked numerous times with different exclusion strategy objects
329 * then the exclusion strategies that were added will be applied as a disjunction rule.
330 * This means that if one of the added exclusion strategies suggests that a field (or
331 * class) should be skipped then that field (or object) is skipped during its
334 * @param strategy an exclusion strategy to apply during deserialization.
335 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
338 public GsonBuilder
addDeserializationExclusionStrategy(ExclusionStrategy strategy
) {
339 excluder
= excluder
.withExclusionStrategy(strategy
, false, true);
344 * Configures Gson to output Json that fits in a page for pretty printing. This option only
345 * affects Json serialization.
347 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
349 public GsonBuilder
setPrettyPrinting() {
350 prettyPrinting
= true;
355 * By default, Gson escapes HTML characters such as < > etc. Use this option to configure
356 * Gson to pass-through HTML characters as is.
358 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
361 public GsonBuilder
disableHtmlEscaping() {
362 this.escapeHtmlChars
= false;
367 * Configures Gson to serialize {@code Date} objects according to the pattern provided. You can
368 * call this method or {@link #setDateFormat(int)} multiple times, but only the last invocation
369 * will be used to decide the serialization format.
371 * <p>The date format will be used to serialize and deserialize {@link java.util.Date}, {@link
372 * java.sql.Timestamp} and {@link java.sql.Date}.
374 * <p>Note that this pattern must abide by the convention provided by {@code SimpleDateFormat}
375 * class. See the documentation in {@link java.text.SimpleDateFormat} for more information on
376 * valid date and time patterns.</p>
378 * @param pattern the pattern that dates will be serialized/deserialized to/from
379 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
382 public GsonBuilder
setDateFormat(String pattern
) {
383 // TODO(Joel): Make this fail fast if it is an invalid date format
384 this.datePattern
= pattern
;
389 * Configures Gson to to serialize {@code Date} objects according to the style value provided.
390 * You can call this method or {@link #setDateFormat(String)} multiple times, but only the last
391 * invocation will be used to decide the serialization format.
393 * <p>Note that this style value should be one of the predefined constants in the
394 * {@code DateFormat} class. See the documentation in {@link java.text.DateFormat} for more
395 * information on the valid style constants.</p>
397 * @param style the predefined date style that date objects will be serialized/deserialized
399 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
402 public GsonBuilder
setDateFormat(int style
) {
403 this.dateStyle
= style
;
404 this.datePattern
= null;
409 * Configures Gson to to serialize {@code Date} objects according to the style value provided.
410 * You can call this method or {@link #setDateFormat(String)} multiple times, but only the last
411 * invocation will be used to decide the serialization format.
413 * <p>Note that this style value should be one of the predefined constants in the
414 * {@code DateFormat} class. See the documentation in {@link java.text.DateFormat} for more
415 * information on the valid style constants.</p>
417 * @param dateStyle the predefined date style that date objects will be serialized/deserialized
419 * @param timeStyle the predefined style for the time portion of the date objects
420 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
423 public GsonBuilder
setDateFormat(int dateStyle
, int timeStyle
) {
424 this.dateStyle
= dateStyle
;
425 this.timeStyle
= timeStyle
;
426 this.datePattern
= null;
431 * Configures Gson for custom serialization or deserialization. This method combines the
432 * registration of an {@link TypeAdapter}, {@link InstanceCreator}, {@link JsonSerializer}, and a
433 * {@link JsonDeserializer}. It is best used when a single object {@code typeAdapter} implements
434 * all the required interfaces for custom serialization with Gson. If a type adapter was
435 * previously registered for the specified {@code type}, it is overwritten.
437 * <p>This registers the type specified and no other types: you must manually register related
438 * types! For example, applications registering {@code boolean.class} should also register {@code
441 * @param type the type definition for the type adapter being registered
442 * @param typeAdapter This object must implement at least one of the {@link TypeAdapter},
443 * {@link InstanceCreator}, {@link JsonSerializer}, and a {@link JsonDeserializer} interfaces.
444 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
446 @SuppressWarnings({"unchecked", "rawtypes"})
447 public GsonBuilder
registerTypeAdapter(Type type
, Object typeAdapter
) {
448 $Gson$Preconditions
.checkArgument(typeAdapter
instanceof JsonSerializer
<?
>
449 || typeAdapter
instanceof JsonDeserializer
<?
>
450 || typeAdapter
instanceof InstanceCreator
<?
>
451 || typeAdapter
instanceof TypeAdapter
<?
>);
452 if (typeAdapter
instanceof InstanceCreator
<?
>) {
453 instanceCreators
.put(type
, (InstanceCreator
) typeAdapter
);
455 if (typeAdapter
instanceof JsonSerializer
<?
> || typeAdapter
instanceof JsonDeserializer
<?
>) {
456 TypeToken
<?
> typeToken
= TypeToken
.get(type
);
457 factories
.add(TreeTypeAdapter
.newFactoryWithMatchRawType(typeToken
, typeAdapter
));
459 if (typeAdapter
instanceof TypeAdapter
<?
>) {
460 factories
.add(TypeAdapters
.newFactory(TypeToken
.get(type
), (TypeAdapter
)typeAdapter
));
466 * Register a factory for type adapters. Registering a factory is useful when the type
467 * adapter needs to be configured based on the type of the field being processed. Gson
468 * is designed to handle a large number of factories, so you should consider registering
469 * them to be at par with registering an individual type adapter.
473 public GsonBuilder
registerTypeAdapterFactory(TypeAdapterFactory factory
) {
474 factories
.add(factory
);
479 * Configures Gson for custom serialization or deserialization for an inheritance type hierarchy.
480 * This method combines the registration of a {@link TypeAdapter}, {@link JsonSerializer} and
481 * a {@link JsonDeserializer}. If a type adapter was previously registered for the specified
482 * type hierarchy, it is overridden. If a type adapter is registered for a specific type in
483 * the type hierarchy, it will be invoked instead of the one registered for the type hierarchy.
485 * @param baseType the class definition for the type adapter being registered for the base class
487 * @param typeAdapter This object must implement at least one of {@link TypeAdapter},
488 * {@link JsonSerializer} or {@link JsonDeserializer} interfaces.
489 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
492 @SuppressWarnings({"unchecked", "rawtypes"})
493 public GsonBuilder
registerTypeHierarchyAdapter(Class
<?
> baseType
, Object typeAdapter
) {
494 $Gson$Preconditions
.checkArgument(typeAdapter
instanceof JsonSerializer
<?
>
495 || typeAdapter
instanceof JsonDeserializer
<?
>
496 || typeAdapter
instanceof TypeAdapter
<?
>);
497 if (typeAdapter
instanceof JsonDeserializer
|| typeAdapter
instanceof JsonSerializer
) {
498 hierarchyFactories
.add(0,
499 TreeTypeAdapter
.newTypeHierarchyFactory(baseType
, typeAdapter
));
501 if (typeAdapter
instanceof TypeAdapter
<?
>) {
502 factories
.add(TypeAdapters
.newTypeHierarchyFactory(baseType
, (TypeAdapter
)typeAdapter
));
508 * Section 2.4 of <a href="http://www.ietf.org/rfc/rfc4627.txt">JSON specification</a> disallows
509 * special double values (NaN, Infinity, -Infinity). However,
510 * <a href="http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-262.pdf">Javascript
511 * specification</a> (see section 4.3.20, 4.3.22, 4.3.23) allows these values as valid Javascript
512 * values. Moreover, most JavaScript engines will accept these special values in JSON without
513 * problem. So, at a practical level, it makes sense to accept these values as valid JSON even
514 * though JSON specification disallows them.
516 * <p>Gson always accepts these special values during deserialization. However, it outputs
517 * strictly compliant JSON. Hence, if it encounters a float value {@link Float#NaN},
518 * {@link Float#POSITIVE_INFINITY}, {@link Float#NEGATIVE_INFINITY}, or a double value
519 * {@link Double#NaN}, {@link Double#POSITIVE_INFINITY}, {@link Double#NEGATIVE_INFINITY}, it
520 * will throw an {@link IllegalArgumentException}. This method provides a way to override the
521 * default behavior when you know that the JSON receiver will be able to handle these special
524 * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern
527 public GsonBuilder
serializeSpecialFloatingPointValues() {
528 this.serializeSpecialFloatingPointValues
= true;
533 * Creates a {@link Gson} instance based on the current configuration. This method is free of
534 * side-effects to this {@code GsonBuilder} instance and hence can be called multiple times.
536 * @return an instance of Gson configured with the options currently set in this builder
538 public Gson
create() {
539 List
<TypeAdapterFactory
> factories
= new ArrayList
<TypeAdapterFactory
>();
540 factories
.addAll(this.factories
);
541 Collections
.reverse(factories
);
542 factories
.addAll(this.hierarchyFactories
);
543 addTypeAdaptersForDate(datePattern
, dateStyle
, timeStyle
, factories
);
545 return new Gson(excluder
, fieldNamingPolicy
, instanceCreators
,
546 serializeNulls
, complexMapKeySerialization
,
547 generateNonExecutableJson
, escapeHtmlChars
, prettyPrinting
,
548 serializeSpecialFloatingPointValues
, longSerializationPolicy
, factories
);
551 private void addTypeAdaptersForDate(String datePattern
, int dateStyle
, int timeStyle
,
552 List
<TypeAdapterFactory
> factories
) {
553 DefaultDateTypeAdapter dateTypeAdapter
;
554 if (datePattern
!= null && !"".equals(datePattern
.trim())) {
555 dateTypeAdapter
= new DefaultDateTypeAdapter(datePattern
);
556 } else if (dateStyle
!= DateFormat
.DEFAULT
&& timeStyle
!= DateFormat
.DEFAULT
) {
557 dateTypeAdapter
= new DefaultDateTypeAdapter(dateStyle
, timeStyle
);
562 factories
.add(TreeTypeAdapter
.newFactory(TypeToken
.get(Date
.class), dateTypeAdapter
));
563 factories
.add(TreeTypeAdapter
.newFactory(TypeToken
.get(Timestamp
.class), dateTypeAdapter
));
564 factories
.add(TreeTypeAdapter
.newFactory(TypeToken
.get(java
.sql
.Date
.class), dateTypeAdapter
));