/* * 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* * The above code prints this JSON object: * *original = new LinkedHashMap (); * original.put(new Point(5, 6), "a"); * original.put(new Point(8, 8), "b"); * System.out.println(gson.toJson(original, type)); * } *
* {@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.
*
*