/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package cn.emay.sdk.util.json.gson; import static cn.emay.sdk.util.json.gson.Gson.DEFAULT_COMPLEX_MAP_KEYS; import static cn.emay.sdk.util.json.gson.Gson.DEFAULT_ESCAPE_HTML; import static cn.emay.sdk.util.json.gson.Gson.DEFAULT_JSON_NON_EXECUTABLE; import static cn.emay.sdk.util.json.gson.Gson.DEFAULT_LENIENT; import static cn.emay.sdk.util.json.gson.Gson.DEFAULT_PRETTY_PRINT; import static cn.emay.sdk.util.json.gson.Gson.DEFAULT_SERIALIZE_NULLS; import static cn.emay.sdk.util.json.gson.Gson.DEFAULT_SPECIALIZE_FLOAT_VALUES; import java.lang.reflect.Type; import java.sql.Timestamp; import java.text.DateFormat; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import cn.emay.sdk.util.json.gson.internal.$Gson$Preconditions; import cn.emay.sdk.util.json.gson.internal.Excluder; import cn.emay.sdk.util.json.gson.internal.bind.TypeAdapters; import cn.emay.sdk.util.json.gson.reflect.TypeToken; import cn.emay.sdk.util.json.gson.stream.JsonReader; /** *
* Use this builder to construct a {@link Gson} instance when you need to set * configuration options other than the default. For {@link Gson} with default * configuration, it is simpler to use {@code new Gson()}. {@code GsonBuilder} * is best used by creating it, and then invoking its various configuration * methods, and finally calling create. *
* ** The following is an example shows how to use the {@code GsonBuilder} to * construct a Gson instance: * *
* Gson gson = new GsonBuilder().registerTypeAdapter(Id.class, new IdTypeAdapter()).enableComplexMapKeySerialization().serializeNulls().setDateFormat(DateFormat.LONG) * .setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE).setPrettyPrinting().setVersion(1.0).create(); ** * *
* NOTES: *
* Below is an example: * *
	 * {
	 * 	@code
	 * 	Gson gson = new GsonBuilder().register(Point.class, new MyPointTypeAdapter()).enableComplexMapKeySerialization().create();
	 *
	 * 	Map original = new LinkedHashMap();
	 * 	original.put(new Point(5, 6), "a");
	 * 	original.put(new Point(8, 8), "b");
	 * 	System.out.println(gson.toJson(original, type));
	 * }
	 *   
	 * 
	 * The above code prints this JSON object:
	 * 
	 * 
	 *   {@code
	 *   {
	 *     "(5,6)": "a",
	 *     "(8,8)": "b"
	 *   }
	 * }
	 * 
	 *
	 * 
	 * Given the assumption above, a {@code Map 
	 * Below is an example of serializing complex types as JSON arrays:
	 * 
	 *  
	 * The date format will be used to serialize and deserialize
	 * {@link java.util.Date}, {@link java.sql.Timestamp} and {@link java.sql.Date}.
	 *
	 *  
	 * Note that this pattern must abide by the convention provided by
	 * {@code SimpleDateFormat} class. See the documentation in
	 * {@link java.text.SimpleDateFormat} for more information on valid date and
	 * time patterns.
	 *  
	 * Note that this style value should be one of the predefined constants in the
	 * {@code DateFormat} class. See the documentation in
	 * {@link java.text.DateFormat} for more information on the valid style
	 * constants.
	 *  
	 * Note that this style value should be one of the predefined constants in the
	 * {@code DateFormat} class. See the documentation in
	 * {@link java.text.DateFormat} for more information on the valid style
	 * constants.
	 *  
	 * This registers the type specified and no other types: you must manually
	 * register related types! For example, applications registering
	 * {@code boolean.class} should also register {@code
	 * Boolean.class}.
	 *
	 * @param type
	 *            the type definition for the type adapter being registered
	 * @param typeAdapter
	 *            This object must implement at least one of the
	 *            {@link TypeAdapter}, {@link InstanceCreator},
	 *            {@link JsonSerializer}, and a {@link JsonDeserializer} interfaces.
	 * @return a reference to this {@code GsonBuilder} object to fulfill the
	 *         "Builder" pattern
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public GsonBuilder registerTypeAdapter(Type type, Object typeAdapter) {
		$Gson$Preconditions.checkArgument(
				typeAdapter instanceof JsonSerializer> || typeAdapter instanceof JsonDeserializer> || typeAdapter instanceof InstanceCreator> || typeAdapter instanceof TypeAdapter>);
		if (typeAdapter instanceof InstanceCreator>) {
			instanceCreators.put(type, (InstanceCreator) typeAdapter);
		}
		if (typeAdapter instanceof JsonSerializer> || typeAdapter instanceof JsonDeserializer>) {
			TypeToken> typeToken = TypeToken.get(type);
			factories.add(TreeTypeAdapter.newFactoryWithMatchRawType(typeToken, typeAdapter));
		}
		if (typeAdapter instanceof TypeAdapter>) {
			factories.add(TypeAdapters.newFactory(TypeToken.get(type), (TypeAdapter) typeAdapter));
		}
		return this;
	}
	/**
	 * Register a factory for type adapters. Registering a factory is useful when
	 * the type adapter needs to be configured based on the type of the field being
	 * processed. Gson is designed to handle a large number of factories, so you
	 * should consider registering them to be at par with registering an individual
	 * type adapter.
	 *
	 * @since 2.1
	 */
	public GsonBuilder registerTypeAdapterFactory(TypeAdapterFactory factory) {
		factories.add(factory);
		return this;
	}
	/**
	 * Configures Gson for custom serialization or deserialization for an
	 * inheritance type hierarchy. This method combines the registration of a
	 * {@link TypeAdapter}, {@link JsonSerializer} and a {@link JsonDeserializer}.
	 * If a type adapter was previously registered for the specified type hierarchy,
	 * it is overridden. If a type adapter is registered for a specific type in the
	 * type hierarchy, it will be invoked instead of the one registered for the type
	 * hierarchy.
	 *
	 * @param baseType
	 *            the class definition for the type adapter being registered for the
	 *            base class or interface
	 * @param typeAdapter
	 *            This object must implement at least one of {@link TypeAdapter},
	 *            {@link JsonSerializer} or {@link JsonDeserializer} interfaces.
	 * @return a reference to this {@code GsonBuilder} object to fulfill the
	 *         "Builder" pattern
	 * @since 1.7
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public GsonBuilder registerTypeHierarchyAdapter(Class> baseType, Object typeAdapter) {
		$Gson$Preconditions.checkArgument(typeAdapter instanceof JsonSerializer> || typeAdapter instanceof JsonDeserializer> || typeAdapter instanceof TypeAdapter>);
		if (typeAdapter instanceof JsonDeserializer || typeAdapter instanceof JsonSerializer) {
			hierarchyFactories.add(0, TreeTypeAdapter.newTypeHierarchyFactory(baseType, typeAdapter));
		}
		if (typeAdapter instanceof TypeAdapter>) {
			factories.add(TypeAdapters.newTypeHierarchyFactory(baseType, (TypeAdapter) typeAdapter));
		}
		return this;
	}
	/**
	 * Section 2.4 of JSON
	 * specification disallows special double values (NaN, Infinity, -Infinity).
	 * However, Javascript
	 * specification (see section 4.3.20, 4.3.22, 4.3.23) allows these values as
	 * valid Javascript values. Moreover, most JavaScript engines will accept these
	 * special values in JSON without problem. So, at a practical level, it makes
	 * sense to accept these values as valid JSON even though JSON specification
	 * disallows them.
	 *
	 *  
	 * Gson always accepts these special values during deserialization. However, it
	 * outputs strictly compliant JSON. Hence, if it encounters a float value
	 * {@link Float#NaN}, {@link Float#POSITIVE_INFINITY},
	 * {@link Float#NEGATIVE_INFINITY}, or a double value {@link Double#NaN},
	 * {@link Double#POSITIVE_INFINITY}, {@link Double#NEGATIVE_INFINITY}, it will
	 * throw an {@link IllegalArgumentException}. This method provides a way to
	 * override the default behavior when you know that the JSON receiver will be
	 * able to handle these special values.
	 *
	 * @return a reference to this {@code GsonBuilder} object to fulfill the
	 *         "Builder" pattern
	 * @since 1.3
	 */
	public GsonBuilder serializeSpecialFloatingPointValues() {
		this.serializeSpecialFloatingPointValues = true;
		return this;
	}
	/**
	 * Creates a {@link Gson} instance based on the current configuration. This
	 * method is free of side-effects to this {@code GsonBuilder} instance and hence
	 * can be called multiple times.
	 *
	 * @return an instance of Gson configured with the options currently set in this
	 *         builder
	 */
	public Gson create() {
		List
	 *  {@code
	 *   Gson gson = new GsonBuilder()
	 *       .enableComplexMapKeySerialization()
	 *       .create();
	 *
	 *   Map   {@code
	 *   [
	 *     [
	 *       {
	 *         "x": 5,
	 *         "y": 6
	 *       },
	 *       "a"
	 *     ],
	 *     [
	 *       {
	 *         "x": 8,
	 *         "y": 8
	 *       },
	 *       "b"
	 *     ]
	 *   ]
	 * }
	 * 
	 *
	 * @return a reference to this {@code GsonBuilder} object to fulfill the
	 *         "Builder" pattern
	 * @since 1.7
	 */
	public GsonBuilder enableComplexMapKeySerialization() {
		complexMapKeySerialization = true;
		return this;
	}
	/**
	 * Configures Gson to exclude inner classes during serialization.
	 *
	 * @return a reference to this {@code GsonBuilder} object to fulfill the
	 *         "Builder" pattern
	 * @since 1.3
	 */
	public GsonBuilder disableInnerClassSerialization() {
		excluder = excluder.disableInnerClassSerialization();
		return this;
	}
	/**
	 * Configures Gson to apply a specific serialization policy for {@code Long} and
	 * {@code long} objects.
	 *
	 * @param serializationPolicy
	 *            the particular policy to use for serializing longs.
	 * @return a reference to this {@code GsonBuilder} object to fulfill the
	 *         "Builder" pattern
	 * @since 1.3
	 */
	public GsonBuilder setLongSerializationPolicy(LongSerializationPolicy serializationPolicy) {
		this.longSerializationPolicy = serializationPolicy;
		return this;
	}
	/**
	 * Configures Gson to apply a specific naming policy to an object's field during
	 * serialization and deserialization.
	 *
	 * @param namingConvention
	 *            the JSON field naming convention to use for serialization and
	 *            deserialization.
	 * @return a reference to this {@code GsonBuilder} object to fulfill the
	 *         "Builder" pattern
	 */
	public GsonBuilder setFieldNamingPolicy(FieldNamingPolicy namingConvention) {
		this.fieldNamingPolicy = namingConvention;
		return this;
	}
	/**
	 * Configures Gson to apply a specific naming policy strategy to an object's
	 * field during serialization and deserialization.
	 *
	 * @param fieldNamingStrategy
	 *            the actual naming strategy to apply to the fields
	 * @return a reference to this {@code GsonBuilder} object to fulfill the
	 *         "Builder" pattern
	 * @since 1.3
	 */
	public GsonBuilder setFieldNamingStrategy(FieldNamingStrategy fieldNamingStrategy) {
		this.fieldNamingPolicy = fieldNamingStrategy;
		return this;
	}
	/**
	 * Configures Gson to apply a set of exclusion strategies during both
	 * serialization and deserialization. Each of the {@code strategies} will be
	 * applied as a disjunction rule. This means that if one of the
	 * {@code strategies} suggests that a field (or class) should be skipped then
	 * that field (or object) is skipped during serialization/deserialization.
	 *
	 * @param strategies
	 *            the set of strategy object to apply during object
	 *            (de)serialization.
	 * @return a reference to this {@code GsonBuilder} object to fulfill the
	 *         "Builder" pattern
	 * @since 1.4
	 */
	public GsonBuilder setExclusionStrategies(ExclusionStrategy... strategies) {
		for (ExclusionStrategy strategy : strategies) {
			excluder = excluder.withExclusionStrategy(strategy, true, true);
		}
		return this;
	}
	/**
	 * Configures Gson to apply the passed in exclusion strategy during
	 * serialization. If this method is invoked numerous times with different
	 * exclusion strategy objects then the exclusion strategies that were added will
	 * be applied as a disjunction rule. This means that if one of the added
	 * exclusion strategies suggests that a field (or class) should be skipped then
	 * that field (or object) is skipped during its serialization.
	 *
	 * @param strategy
	 *            an exclusion strategy to apply during serialization.
	 * @return a reference to this {@code GsonBuilder} object to fulfill the
	 *         "Builder" pattern
	 * @since 1.7
	 */
	public GsonBuilder addSerializationExclusionStrategy(ExclusionStrategy strategy) {
		excluder = excluder.withExclusionStrategy(strategy, true, false);
		return this;
	}
	/**
	 * Configures Gson to apply the passed in exclusion strategy during
	 * deserialization. If this method is invoked numerous times with different
	 * exclusion strategy objects then the exclusion strategies that were added will
	 * be applied as a disjunction rule. This means that if one of the added
	 * exclusion strategies suggests that a field (or class) should be skipped then
	 * that field (or object) is skipped during its deserialization.
	 *
	 * @param strategy
	 *            an exclusion strategy to apply during deserialization.
	 * @return a reference to this {@code GsonBuilder} object to fulfill the
	 *         "Builder" pattern
	 * @since 1.7
	 */
	public GsonBuilder addDeserializationExclusionStrategy(ExclusionStrategy strategy) {
		excluder = excluder.withExclusionStrategy(strategy, false, true);
		return this;
	}
	/**
	 * Configures Gson to output Json that fits in a page for pretty printing. This
	 * option only affects Json serialization.
	 *
	 * @return a reference to this {@code GsonBuilder} object to fulfill the
	 *         "Builder" pattern
	 */
	public GsonBuilder setPrettyPrinting() {
		prettyPrinting = true;
		return this;
	}
	/**
	 * By default, Gson is strict and only accepts JSON as specified by
	 * RFC 4627. This option makes
	 * the parser liberal in what it accepts.
	 *
	 * @return a reference to this {@code GsonBuilder} object to fulfill the
	 *         "Builder" pattern
	 * @see JsonReader#setLenient(boolean)
	 */
	public GsonBuilder setLenient() {
		lenient = true;
		return this;
	}
	/**
	 * By default, Gson escapes HTML characters such as < > etc. Use this
	 * option to configure Gson to pass-through HTML characters as is.
	 *
	 * @return a reference to this {@code GsonBuilder} object to fulfill the
	 *         "Builder" pattern
	 * @since 1.3
	 */
	public GsonBuilder disableHtmlEscaping() {
		this.escapeHtmlChars = false;
		return this;
	}
	/**
	 * Configures Gson to serialize {@code Date} objects according to the pattern
	 * provided. You can call this method or {@link #setDateFormat(int)} multiple
	 * times, but only the last invocation will be used to decide the serialization
	 * format.
	 *
	 *