]>
Commit | Line | Data |
---|---|---|
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.TypeAdapters; | |
32 | import com.google.gson.reflect.TypeToken; | |
33 | ||
34 | /** | |
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> | |
39 | * | |
40 | * <p>The following is an example shows how to use the {@code GsonBuilder} to construct a Gson | |
41 | * instance: | |
42 | * | |
43 | * <pre> | |
44 | * Gson gson = new GsonBuilder() | |
45 | * .registerTypeAdapter(Id.class, new IdTypeAdapter()) | |
46 | * .enableComplexMapKeySerialization() | |
47 | * .serializeNulls() | |
48 | * .setDateFormat(DateFormat.LONG) | |
49 | * .setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE) | |
50 | * .setPrettyPrinting() | |
51 | * .setVersion(1.0) | |
52 | * .create(); | |
53 | * </pre></p> | |
54 | * | |
55 | * <p>NOTES: | |
56 | * <ul> | |
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> | |
61 | * </ul> | |
62 | * </p> | |
63 | * | |
64 | * @author Inderjeet Singh | |
65 | * @author Joel Leitch | |
66 | * @author Jesse Wilson | |
67 | */ | |
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; | |
86 | ||
87 | /** | |
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 | |
91 | * {@link #create()}. | |
92 | */ | |
93 | public GsonBuilder() { | |
94 | } | |
95 | ||
96 | /** | |
97 | * Configures Gson to enable versioning support. | |
98 | * | |
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 | |
102 | */ | |
103 | public GsonBuilder setVersion(double ignoreVersionsAfter) { | |
104 | excluder = excluder.withVersion(ignoreVersionsAfter); | |
105 | return this; | |
106 | } | |
107 | ||
108 | /** | |
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 | |
111 | * behavior. | |
112 | * | |
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 | |
118 | */ | |
119 | public GsonBuilder excludeFieldsWithModifiers(int... modifiers) { | |
120 | excluder = excluder.withModifiers(modifiers); | |
121 | return this; | |
122 | } | |
123 | ||
124 | /** | |
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> | |
128 | * for details. | |
129 | * | |
130 | * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern | |
131 | * @since 1.3 | |
132 | */ | |
133 | public GsonBuilder generateNonExecutableJson() { | |
134 | this.generateNonExecutableJson = true; | |
135 | return this; | |
136 | } | |
137 | ||
138 | /** | |
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. | |
141 | * | |
142 | * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern | |
143 | */ | |
144 | public GsonBuilder excludeFieldsWithoutExposeAnnotation() { | |
145 | excluder = excluder.excludeFieldsWithoutExposeAnnotation(); | |
146 | return this; | |
147 | } | |
148 | ||
149 | /** | |
150 | * Configure Gson to serialize null fields. By default, Gson omits all fields that are null | |
151 | * during serialization. | |
152 | * | |
153 | * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern | |
154 | * @since 1.2 | |
155 | */ | |
156 | public GsonBuilder serializeNulls() { | |
157 | this.serializeNulls = true; | |
158 | return this; | |
159 | } | |
160 | ||
161 | /** | |
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 | |
166 | * apply: | |
167 | * | |
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}. | |
173 | * | |
174 | * <p>Below is an example: | |
175 | * <pre> {@code | |
176 | * Gson gson = new GsonBuilder() | |
177 | * .register(Point.class, new MyPointTypeAdapter()) | |
178 | * .enableComplexMapKeySerialization() | |
179 | * .create(); | |
180 | * | |
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)); | |
185 | * }</pre> | |
186 | * The above code prints this JSON object:<pre> {@code | |
187 | * { | |
188 | * "(5,6)": "a", | |
189 | * "(8,8)": "b" | |
190 | * } | |
191 | * }</pre> | |
192 | * | |
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 | |
197 | * {"x":2,"y":5}}. | |
198 | * | |
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). | |
201 | * | |
202 | * <p>Below is an example of serializing complex types as JSON arrays: | |
203 | * <pre> {@code | |
204 | * Gson gson = new GsonBuilder() | |
205 | * .enableComplexMapKeySerialization() | |
206 | * .create(); | |
207 | * | |
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)); | |
212 | * } | |
213 | * | |
214 | * The JSON output would look as follows: | |
215 | * <pre> {@code | |
216 | * [ | |
217 | * [ | |
218 | * { | |
219 | * "x": 5, | |
220 | * "y": 6 | |
221 | * }, | |
222 | * "a" | |
223 | * ], | |
224 | * [ | |
225 | * { | |
226 | * "x": 8, | |
227 | * "y": 8 | |
228 | * }, | |
229 | * "b" | |
230 | * ] | |
231 | * ] | |
232 | * }</pre> | |
233 | * | |
234 | * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern | |
235 | * @since 1.7 | |
236 | */ | |
237 | public GsonBuilder enableComplexMapKeySerialization() { | |
238 | complexMapKeySerialization = true; | |
239 | return this; | |
240 | } | |
241 | ||
242 | /** | |
243 | * Configures Gson to exclude inner classes during serialization. | |
244 | * | |
245 | * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern | |
246 | * @since 1.3 | |
247 | */ | |
248 | public GsonBuilder disableInnerClassSerialization() { | |
249 | excluder = excluder.disableInnerClassSerialization(); | |
250 | return this; | |
251 | } | |
252 | ||
253 | /** | |
254 | * Configures Gson to apply a specific serialization policy for {@code Long} and {@code long} | |
255 | * objects. | |
256 | * | |
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 | |
259 | * @since 1.3 | |
260 | */ | |
261 | public GsonBuilder setLongSerializationPolicy(LongSerializationPolicy serializationPolicy) { | |
262 | this.longSerializationPolicy = serializationPolicy; | |
263 | return this; | |
264 | } | |
265 | ||
266 | /** | |
267 | * Configures Gson to apply a specific naming policy to an object's field during serialization | |
268 | * and deserialization. | |
269 | * | |
270 | * @param namingConvention the JSON field naming convention to use for serialization and | |
271 | * deserialization. | |
272 | * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern | |
273 | */ | |
274 | public GsonBuilder setFieldNamingPolicy(FieldNamingPolicy namingConvention) { | |
275 | this.fieldNamingPolicy = namingConvention; | |
276 | return this; | |
277 | } | |
278 | ||
279 | /** | |
280 | * Configures Gson to apply a specific naming policy strategy to an object's field during | |
281 | * serialization and deserialization. | |
282 | * | |
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 | |
285 | * @since 1.3 | |
286 | */ | |
287 | public GsonBuilder setFieldNamingStrategy(FieldNamingStrategy fieldNamingStrategy) { | |
288 | this.fieldNamingPolicy = fieldNamingStrategy; | |
289 | return this; | |
290 | } | |
291 | ||
292 | /** | |
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. | |
297 | * | |
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 | |
300 | * @since 1.4 | |
301 | */ | |
302 | public GsonBuilder setExclusionStrategies(ExclusionStrategy... strategies) { | |
303 | for (ExclusionStrategy strategy : strategies) { | |
304 | excluder = excluder.withExclusionStrategy(strategy, true, true); | |
305 | } | |
306 | return this; | |
307 | } | |
308 | ||
309 | /** | |
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 | |
315 | * serialization. | |
316 | * | |
317 | * @param strategy an exclusion strategy to apply during serialization. | |
318 | * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern | |
319 | * @since 1.7 | |
320 | */ | |
321 | public GsonBuilder addSerializationExclusionStrategy(ExclusionStrategy strategy) { | |
322 | excluder = excluder.withExclusionStrategy(strategy, true, false); | |
323 | return this; | |
324 | } | |
325 | ||
326 | /** | |
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 | |
332 | * deserialization. | |
333 | * | |
334 | * @param strategy an exclusion strategy to apply during deserialization. | |
335 | * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern | |
336 | * @since 1.7 | |
337 | */ | |
338 | public GsonBuilder addDeserializationExclusionStrategy(ExclusionStrategy strategy) { | |
339 | excluder = excluder.withExclusionStrategy(strategy, false, true); | |
340 | return this; | |
341 | } | |
342 | ||
343 | /** | |
344 | * Configures Gson to output Json that fits in a page for pretty printing. This option only | |
345 | * affects Json serialization. | |
346 | * | |
347 | * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern | |
348 | */ | |
349 | public GsonBuilder setPrettyPrinting() { | |
350 | prettyPrinting = true; | |
351 | return this; | |
352 | } | |
353 | ||
354 | /** | |
355 | * By default, Gson escapes HTML characters such as < > etc. Use this option to configure | |
356 | * Gson to pass-through HTML characters as is. | |
357 | * | |
358 | * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern | |
359 | * @since 1.3 | |
360 | */ | |
361 | public GsonBuilder disableHtmlEscaping() { | |
362 | this.escapeHtmlChars = false; | |
363 | return this; | |
364 | } | |
365 | ||
366 | /** | |
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. | |
370 | * | |
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}. | |
373 | * | |
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> | |
377 | * | |
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 | |
380 | * @since 1.2 | |
381 | */ | |
382 | public GsonBuilder setDateFormat(String pattern) { | |
383 | // TODO(Joel): Make this fail fast if it is an invalid date format | |
384 | this.datePattern = pattern; | |
385 | return this; | |
386 | } | |
387 | ||
388 | /** | |
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. | |
392 | * | |
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> | |
396 | * | |
397 | * @param style the predefined date style that date objects will be serialized/deserialized | |
398 | * to/from | |
399 | * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern | |
400 | * @since 1.2 | |
401 | */ | |
402 | public GsonBuilder setDateFormat(int style) { | |
403 | this.dateStyle = style; | |
404 | this.datePattern = null; | |
405 | return this; | |
406 | } | |
407 | ||
408 | /** | |
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. | |
412 | * | |
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> | |
416 | * | |
417 | * @param dateStyle the predefined date style that date objects will be serialized/deserialized | |
418 | * to/from | |
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 | |
421 | * @since 1.2 | |
422 | */ | |
423 | public GsonBuilder setDateFormat(int dateStyle, int timeStyle) { | |
424 | this.dateStyle = dateStyle; | |
425 | this.timeStyle = timeStyle; | |
426 | this.datePattern = null; | |
427 | return this; | |
428 | } | |
429 | ||
430 | /** | |
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. | |
436 | * | |
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 | |
439 | * Boolean.class}. | |
440 | * | |
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 | |
445 | */ | |
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); | |
454 | } | |
455 | if (typeAdapter instanceof JsonSerializer<?> || typeAdapter instanceof JsonDeserializer<?>) { | |
456 | TypeToken<?> typeToken = TypeToken.get(type); | |
457 | factories.add(TreeTypeAdapter.newFactoryWithMatchRawType(typeToken, typeAdapter)); | |
458 | } | |
459 | if (typeAdapter instanceof TypeAdapter<?>) { | |
460 | factories.add(TypeAdapters.newFactory(TypeToken.get(type), (TypeAdapter)typeAdapter)); | |
461 | } | |
462 | return this; | |
463 | } | |
464 | ||
465 | /** | |
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. | |
470 | * | |
471 | * @since 2.1 | |
472 | */ | |
473 | public GsonBuilder registerTypeAdapterFactory(TypeAdapterFactory factory) { | |
474 | factories.add(factory); | |
475 | return this; | |
476 | } | |
477 | ||
478 | /** | |
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. | |
484 | * | |
485 | * @param baseType the class definition for the type adapter being registered for the base class | |
486 | * or interface | |
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 | |
490 | * @since 1.7 | |
491 | */ | |
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)); | |
500 | } | |
501 | if (typeAdapter instanceof TypeAdapter<?>) { | |
502 | factories.add(TypeAdapters.newTypeHierarchyFactory(baseType, (TypeAdapter)typeAdapter)); | |
503 | } | |
504 | return this; | |
505 | } | |
506 | ||
507 | /** | |
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. | |
515 | * | |
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 | |
522 | * values. | |
523 | * | |
524 | * @return a reference to this {@code GsonBuilder} object to fulfill the "Builder" pattern | |
525 | * @since 1.3 | |
526 | */ | |
527 | public GsonBuilder serializeSpecialFloatingPointValues() { | |
528 | this.serializeSpecialFloatingPointValues = true; | |
529 | return this; | |
530 | } | |
531 | ||
532 | /** | |
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. | |
535 | * | |
536 | * @return an instance of Gson configured with the options currently set in this builder | |
537 | */ | |
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); | |
544 | ||
545 | return new Gson(excluder, fieldNamingPolicy, instanceCreators, | |
546 | serializeNulls, complexMapKeySerialization, | |
547 | generateNonExecutableJson, escapeHtmlChars, prettyPrinting, | |
548 | serializeSpecialFloatingPointValues, longSerializationPolicy, factories); | |
549 | } | |
550 | ||
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); | |
558 | } else { | |
559 | return; | |
560 | } | |
561 | ||
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)); | |
565 | } | |
566 | } |