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 < > 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