/*
* 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 java.io.EOFException;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicLongArray;
import cn.emay.sdk.util.json.gson.internal.ConstructorConstructor;
import cn.emay.sdk.util.json.gson.internal.Excluder;
import cn.emay.sdk.util.json.gson.internal.Primitives;
import cn.emay.sdk.util.json.gson.internal.Streams;
import cn.emay.sdk.util.json.gson.internal.bind.ArrayTypeAdapter;
import cn.emay.sdk.util.json.gson.internal.bind.CollectionTypeAdapterFactory;
import cn.emay.sdk.util.json.gson.internal.bind.DateTypeAdapter;
import cn.emay.sdk.util.json.gson.internal.bind.JsonAdapterAnnotationTypeAdapterFactory;
import cn.emay.sdk.util.json.gson.internal.bind.JsonTreeReader;
import cn.emay.sdk.util.json.gson.internal.bind.JsonTreeWriter;
import cn.emay.sdk.util.json.gson.internal.bind.MapTypeAdapterFactory;
import cn.emay.sdk.util.json.gson.internal.bind.ObjectTypeAdapter;
import cn.emay.sdk.util.json.gson.internal.bind.ReflectiveTypeAdapterFactory;
import cn.emay.sdk.util.json.gson.internal.bind.SqlDateTypeAdapter;
import cn.emay.sdk.util.json.gson.internal.bind.TimeTypeAdapter;
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;
import cn.emay.sdk.util.json.gson.stream.JsonToken;
import cn.emay.sdk.util.json.gson.stream.JsonWriter;
import cn.emay.sdk.util.json.gson.stream.MalformedJsonException;
/**
* This is the main class for using Gson. Gson is typically used by first
* constructing a Gson instance and then invoking {@link #toJson(Object)} or
* {@link #fromJson(String, Class)} methods on it. Gson instances are
* Thread-safe so you can reuse them freely across multiple threads.
*
*
* You can create a Gson instance by invoking {@code new Gson()} if the default
* configuration is all you need. You can also use {@link GsonBuilder} to build
* a Gson instance with various configuration options such as versioning
* support, pretty printing, custom {@link JsonSerializer}s,
* {@link JsonDeserializer}s, and {@link InstanceCreator}s.
*
*
*
* Here is an example of how Gson is used for a simple Class:
*
*
* Gson gson = new Gson(); // Or use new GsonBuilder().create();
* MyType target = new MyType();
* String json = gson.toJson(target); // serializes target to Json
* MyType target2 = gson.fromJson(json, MyType.class); // deserializes json into target2
*
*
*
*
* If the object that your are serializing/deserializing is a
* {@code ParameterizedType} (i.e. contains at least one type parameter and may
* be an array) then you must use the {@link #toJson(Object, Type)} or
* {@link #fromJson(String, Type)} method. Here is an example for serializing
* and deserializing a {@code ParameterizedType}:
*
*
* Type listType = new TypeToken<List<String>>() {
* }.getType();
* List<String> target = new LinkedList<String>();
* target.add("blah");
*
* Gson gson = new Gson();
* String json = gson.toJson(target, listType);
* List<String> target2 = gson.fromJson(json, listType);
*
*
*
*
* See the Gson
* User Guide for a more complete set of examples.
*
*
* @see com.google.gson.reflect.TypeToken
*
* @author Inderjeet Singh
* @author Joel Leitch
* @author Jesse Wilson
*/
public final class Gson {
static final boolean DEFAULT_JSON_NON_EXECUTABLE = false;
static final boolean DEFAULT_LENIENT = false;
static final boolean DEFAULT_PRETTY_PRINT = false;
static final boolean DEFAULT_ESCAPE_HTML = true;
static final boolean DEFAULT_SERIALIZE_NULLS = false;
static final boolean DEFAULT_COMPLEX_MAP_KEYS = false;
static final boolean DEFAULT_SPECIALIZE_FLOAT_VALUES = false;
private static final String JSON_NON_EXECUTABLE_PREFIX = ")]}'\n";
/**
* This thread local guards against reentrant calls to getAdapter(). In certain
* object graphs, creating an adapter for a type may recursively require an
* adapter for the same type! Without intervention, the recursive lookup would
* stack overflow. We cheat by returning a proxy type adapter. The proxy is
* wired up once the initial adapter has been created.
*/
private final ThreadLocal, FutureTypeAdapter>>> calls = new ThreadLocal, FutureTypeAdapter>>>();
private final Map, TypeAdapter>> typeTokenCache = Collections.synchronizedMap(new HashMap, TypeAdapter>>());
private final List factories;
private final ConstructorConstructor constructorConstructor;
private final boolean serializeNulls;
private final boolean htmlSafe;
private final boolean generateNonExecutableJson;
private final boolean prettyPrinting;
private final boolean lenient;
final JsonDeserializationContext deserializationContext = new JsonDeserializationContext() {
@SuppressWarnings("unchecked")
@Override
public T deserialize(JsonElement json, Type typeOfT) throws JsonParseException {
return (T) fromJson(json, typeOfT);
}
};
final JsonSerializationContext serializationContext = new JsonSerializationContext() {
@Override
public JsonElement serialize(Object src) {
return toJsonTree(src);
}
@Override
public JsonElement serialize(Object src, Type typeOfSrc) {
return toJsonTree(src, typeOfSrc);
}
};
/**
* Constructs a Gson object with default configuration. The default
* configuration has the following settings:
*
* The JSON generated by toJson
methods is in compact
* representation. This means that all the unneeded white-space is removed. You
* can change this behavior with {@link GsonBuilder#setPrettyPrinting()}.
* The generated JSON omits all the fields that are null. Note that nulls in
* arrays are kept as is since an array is an ordered list. Moreover, if a field
* is not null, but its generated JSON is empty, the field is kept. You can
* configure Gson to serialize null values by setting
* {@link GsonBuilder#serializeNulls()}.
* Gson provides default serialization and deserialization for Enums,
* {@link Map}, {@link java.net.URL}, {@link java.net.URI},
* {@link java.util.Locale}, {@link java.util.Date},
* {@link java.math.BigDecimal}, and {@link java.math.BigInteger} classes. If
* you would prefer to change the default representation, you can do so by
* registering a type adapter through
* {@link GsonBuilder#registerTypeAdapter(Type, Object)}.
* The default Date format is same as {@link java.text.DateFormat#DEFAULT}.
* This format ignores the millisecond portion of the date during serialization.
* You can change this by invoking {@link GsonBuilder#setDateFormat(int)} or
* {@link GsonBuilder#setDateFormat(String)}.
* By default, Gson ignores the {@link com.google.gson.annotations.Expose}
* annotation. You can enable Gson to serialize/deserialize only those fields
* marked with this annotation through
* {@link GsonBuilder#excludeFieldsWithoutExposeAnnotation()}.
* By default, Gson ignores the {@link com.google.gson.annotations.Since}
* annotation. You can enable Gson to use this annotation through
* {@link GsonBuilder#setVersion(double)}.
* The default field naming policy for the output Json is same as in Java.
* So, a Java class field versionNumber
will be output as
* "versionNumber"
in Json. The same rules are applied
* for mapping incoming Json to the Java classes. You can change this policy
* through {@link GsonBuilder#setFieldNamingPolicy(FieldNamingPolicy)}.
* By default, Gson excludes transient
or static
* fields from consideration for serialization and deserialization. You can
* change this behavior through
* {@link GsonBuilder#excludeFieldsWithModifiers(int...)}.
*
*/
public Gson() {
this(Excluder.DEFAULT, FieldNamingPolicy.IDENTITY, Collections.>emptyMap(), DEFAULT_SERIALIZE_NULLS, DEFAULT_COMPLEX_MAP_KEYS, DEFAULT_JSON_NON_EXECUTABLE,
DEFAULT_ESCAPE_HTML, DEFAULT_PRETTY_PRINT, DEFAULT_LENIENT, DEFAULT_SPECIALIZE_FLOAT_VALUES, LongSerializationPolicy.DEFAULT, Collections.emptyList());
}
Gson(final Excluder excluder, final FieldNamingStrategy fieldNamingPolicy, final Map> instanceCreators, boolean serializeNulls, boolean complexMapKeySerialization,
boolean generateNonExecutableGson, boolean htmlSafe, boolean prettyPrinting, boolean lenient, boolean serializeSpecialFloatingPointValues, LongSerializationPolicy longSerializationPolicy,
List typeAdapterFactories) {
this.constructorConstructor = new ConstructorConstructor(instanceCreators);
this.serializeNulls = serializeNulls;
this.generateNonExecutableJson = generateNonExecutableGson;
this.htmlSafe = htmlSafe;
this.prettyPrinting = prettyPrinting;
this.lenient = lenient;
List factories = new ArrayList();
// built-in type adapters that cannot be overridden
factories.add(TypeAdapters.JSON_ELEMENT_FACTORY);
factories.add(ObjectTypeAdapter.FACTORY);
// the excluder must precede all adapters that handle user-defined types
factories.add(excluder);
// user's type adapters
factories.addAll(typeAdapterFactories);
// type adapters for basic platform types
factories.add(TypeAdapters.STRING_FACTORY);
factories.add(TypeAdapters.INTEGER_FACTORY);
factories.add(TypeAdapters.BOOLEAN_FACTORY);
factories.add(TypeAdapters.BYTE_FACTORY);
factories.add(TypeAdapters.SHORT_FACTORY);
TypeAdapter longAdapter = longAdapter(longSerializationPolicy);
factories.add(TypeAdapters.newFactory(long.class, Long.class, longAdapter));
factories.add(TypeAdapters.newFactory(double.class, Double.class, doubleAdapter(serializeSpecialFloatingPointValues)));
factories.add(TypeAdapters.newFactory(float.class, Float.class, floatAdapter(serializeSpecialFloatingPointValues)));
factories.add(TypeAdapters.NUMBER_FACTORY);
factories.add(TypeAdapters.ATOMIC_INTEGER_FACTORY);
factories.add(TypeAdapters.ATOMIC_BOOLEAN_FACTORY);
factories.add(TypeAdapters.newFactory(AtomicLong.class, atomicLongAdapter(longAdapter)));
factories.add(TypeAdapters.newFactory(AtomicLongArray.class, atomicLongArrayAdapter(longAdapter)));
factories.add(TypeAdapters.ATOMIC_INTEGER_ARRAY_FACTORY);
factories.add(TypeAdapters.CHARACTER_FACTORY);
factories.add(TypeAdapters.STRING_BUILDER_FACTORY);
factories.add(TypeAdapters.STRING_BUFFER_FACTORY);
factories.add(TypeAdapters.newFactory(BigDecimal.class, TypeAdapters.BIG_DECIMAL));
factories.add(TypeAdapters.newFactory(BigInteger.class, TypeAdapters.BIG_INTEGER));
factories.add(TypeAdapters.URL_FACTORY);
factories.add(TypeAdapters.URI_FACTORY);
factories.add(TypeAdapters.UUID_FACTORY);
factories.add(TypeAdapters.CURRENCY_FACTORY);
factories.add(TypeAdapters.LOCALE_FACTORY);
factories.add(TypeAdapters.INET_ADDRESS_FACTORY);
factories.add(TypeAdapters.BIT_SET_FACTORY);
factories.add(DateTypeAdapter.FACTORY);
factories.add(TypeAdapters.CALENDAR_FACTORY);
factories.add(TimeTypeAdapter.FACTORY);
factories.add(SqlDateTypeAdapter.FACTORY);
factories.add(TypeAdapters.TIMESTAMP_FACTORY);
factories.add(ArrayTypeAdapter.FACTORY);
factories.add(TypeAdapters.CLASS_FACTORY);
// type adapters for composite and user-defined types
factories.add(new CollectionTypeAdapterFactory(constructorConstructor));
factories.add(new MapTypeAdapterFactory(constructorConstructor, complexMapKeySerialization));
factories.add(new JsonAdapterAnnotationTypeAdapterFactory(constructorConstructor));
factories.add(TypeAdapters.ENUM_FACTORY);
factories.add(new ReflectiveTypeAdapterFactory(constructorConstructor, fieldNamingPolicy, excluder));
this.factories = Collections.unmodifiableList(factories);
}
private TypeAdapter doubleAdapter(boolean serializeSpecialFloatingPointValues) {
if (serializeSpecialFloatingPointValues) {
return TypeAdapters.DOUBLE;
}
return new TypeAdapter() {
@Override
public Double read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
return in.nextDouble();
}
@Override
public void write(JsonWriter out, Number value) throws IOException {
if (value == null) {
out.nullValue();
return;
}
double doubleValue = value.doubleValue();
checkValidFloatingPoint(doubleValue);
out.value(value);
}
};
}
private TypeAdapter floatAdapter(boolean serializeSpecialFloatingPointValues) {
if (serializeSpecialFloatingPointValues) {
return TypeAdapters.FLOAT;
}
return new TypeAdapter() {
@Override
public Float read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
return (float) in.nextDouble();
}
@Override
public void write(JsonWriter out, Number value) throws IOException {
if (value == null) {
out.nullValue();
return;
}
float floatValue = value.floatValue();
checkValidFloatingPoint(floatValue);
out.value(value);
}
};
}
static void checkValidFloatingPoint(double value) {
if (Double.isNaN(value) || Double.isInfinite(value)) {
throw new IllegalArgumentException(
value + " is not a valid double value as per JSON specification. To override this" + " behavior, use GsonBuilder.serializeSpecialFloatingPointValues() method.");
}
}
private static TypeAdapter longAdapter(LongSerializationPolicy longSerializationPolicy) {
if (longSerializationPolicy == LongSerializationPolicy.DEFAULT) {
return TypeAdapters.LONG;
}
return new TypeAdapter() {
@Override
public Number read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
return in.nextLong();
}
@Override
public void write(JsonWriter out, Number value) throws IOException {
if (value == null) {
out.nullValue();
return;
}
out.value(value.toString());
}
};
}
private static TypeAdapter atomicLongAdapter(final TypeAdapter longAdapter) {
return new TypeAdapter() {
@Override
public void write(JsonWriter out, AtomicLong value) throws IOException {
longAdapter.write(out, value.get());
}
@Override
public AtomicLong read(JsonReader in) throws IOException {
Number value = longAdapter.read(in);
return new AtomicLong(value.longValue());
}
}.nullSafe();
}
private static TypeAdapter atomicLongArrayAdapter(final TypeAdapter longAdapter) {
return new TypeAdapter() {
@Override
public void write(JsonWriter out, AtomicLongArray value) throws IOException {
out.beginArray();
for (int i = 0, length = value.length(); i < length; i++) {
longAdapter.write(out, value.get(i));
}
out.endArray();
}
@Override
public AtomicLongArray read(JsonReader in) throws IOException {
List list = new ArrayList();
in.beginArray();
while (in.hasNext()) {
long value = longAdapter.read(in).longValue();
list.add(value);
}
in.endArray();
int length = list.size();
AtomicLongArray array = new AtomicLongArray(length);
for (int i = 0; i < length; ++i) {
array.set(i, list.get(i));
}
return array;
}
}.nullSafe();
}
/**
* Returns the type adapter for {@code} type.
*
* @throws IllegalArgumentException
* if this GSON cannot serialize and deserialize {@code type}.
*/
@SuppressWarnings("unchecked")
public TypeAdapter getAdapter(TypeToken type) {
TypeAdapter> cached = typeTokenCache.get(type);
if (cached != null) {
return (TypeAdapter) cached;
}
Map, FutureTypeAdapter>> threadCalls = calls.get();
boolean requiresThreadLocalCleanup = false;
if (threadCalls == null) {
threadCalls = new HashMap, FutureTypeAdapter>>();
calls.set(threadCalls);
requiresThreadLocalCleanup = true;
}
// the key and value type parameters always agree
FutureTypeAdapter ongoingCall = (FutureTypeAdapter) threadCalls.get(type);
if (ongoingCall != null) {
return ongoingCall;
}
try {
FutureTypeAdapter call = new FutureTypeAdapter();
threadCalls.put(type, call);
for (TypeAdapterFactory factory : factories) {
TypeAdapter candidate = factory.create(this, type);
if (candidate != null) {
call.setDelegate(candidate);
typeTokenCache.put(type, candidate);
return candidate;
}
}
throw new IllegalArgumentException("GSON cannot handle " + type);
} finally {
threadCalls.remove(type);
if (requiresThreadLocalCleanup) {
calls.remove();
}
}
}
/**
* This method is used to get an alternate type adapter for the specified type.
* This is used to access a type adapter that is overridden by a
* {@link TypeAdapterFactory} that you may have registered. This features is
* typically used when you want to register a type adapter that does a little
* bit of work but then delegates further processing to the Gson default type
* adapter. Here is an example:
*
* Let's say we want to write a type adapter that counts the number of objects
* being read from or written to JSON. We can achieve this by writing a type
* adapter factory that uses the getDelegateAdapter
method:
*
*
* {
* @code
* class StatsTypeAdapterFactory implements TypeAdapterFactory {
* public int numReads = 0;
* public int numWrites = 0;
*
* public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
* final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
* return new TypeAdapter<T>() {
* public void write(JsonWriter out, T value) throws IOException {
* ++numWrites;
* delegate.write(out, value);
* }
*
* public T read(JsonReader in) throws IOException {
* ++numReads;
* return delegate.read(in);
* }
* };
* }
* }
* }
*
*
* This factory can now be used like this:
*
*
* {
* @code
* StatsTypeAdapterFactory stats = new StatsTypeAdapterFactory();
* Gson gson = new GsonBuilder().registerTypeAdapterFactory(stats).create();
* // Call gson.toJson() and fromJson methods on objects
* System.out.println("Num JSON reads" + stats.numReads);
* System.out.println("Num JSON writes" + stats.numWrites);
* }
*
*
* Note that this call will skip all factories registered before
* {@code skipPast}. In case of multiple TypeAdapterFactories registered it is
* up to the caller of this function to insure that the order of registration
* does not prevent this method from reaching a factory they would expect to
* reply from this call. Note that since you can not override type adapter
* factories for String and Java primitive types, our stats factory will not
* count the number of String or primitives that will be read or written.
*
* @param skipPast
* The type adapter factory that needs to be skipped while searching
* for a matching type adapter. In most cases, you should just pass
* this (the type adapter factory from where
* {@link #getDelegateAdapter} method is being invoked).
* @param type
* Type for which the delegate adapter is being searched for.
*
* @since 2.2
*/
public TypeAdapter getDelegateAdapter(TypeAdapterFactory skipPast, TypeToken type) {
boolean skipPastFound = false;
// Skip past if and only if the specified factory is present in the factories.
// This is useful because the factories created through JsonAdapter annotations
// are not
// registered in this list.
if (!factories.contains(skipPast))
skipPastFound = true;
for (TypeAdapterFactory factory : factories) {
if (!skipPastFound) {
if (factory == skipPast) {
skipPastFound = true;
}
continue;
}
TypeAdapter candidate = factory.create(this, type);
if (candidate != null) {
return candidate;
}
}
throw new IllegalArgumentException("GSON cannot serialize " + type);
}
/**
* Returns the type adapter for {@code} type.
*
* @throws IllegalArgumentException
* if this GSON cannot serialize and deserialize {@code type}.
*/
public TypeAdapter getAdapter(Class type) {
return getAdapter(TypeToken.get(type));
}
/**
* This method serializes the specified object into its equivalent
* representation as a tree of {@link JsonElement}s. This method should be used
* when the specified object is not a generic type. This method uses
* {@link Class#getClass()} to get the type for the specified object, but the
* {@code getClass()} loses the generic type information because of the Type
* Erasure feature of Java. Note that this method works fine if the any of the
* object fields are of generic type, just the object itself should not be of a
* generic type. If the object is of generic type, use
* {@link #toJsonTree(Object, Type)} instead.
*
* @param src
* the object for which Json representation is to be created setting
* for Gson
* @return Json representation of {@code src}.
* @since 1.4
*/
public JsonElement toJsonTree(Object src) {
if (src == null) {
return JsonNull.INSTANCE;
}
return toJsonTree(src, src.getClass());
}
/**
* This method serializes the specified object, including those of generic
* types, into its equivalent representation as a tree of {@link JsonElement}s.
* This method must be used if the specified object is a generic type. For
* non-generic objects, use {@link #toJsonTree(Object)} instead.
*
* @param src
* the object for which JSON representation is to be created
* @param typeOfSrc
* The specific genericized type of src. You can obtain this type by
* using the {@link com.google.gson.reflect.TypeToken} class. For
* example, to get the type for {@code Collection}, you should
* use:
*
*
* Type typeOfSrc = new TypeToken<Collection<Foo>>() {
* }.getType();
*
*
* @return Json representation of {@code src}
* @since 1.4
*/
public JsonElement toJsonTree(Object src, Type typeOfSrc) {
JsonTreeWriter writer = new JsonTreeWriter();
toJson(src, typeOfSrc, writer);
return writer.get();
}
/**
* This method serializes the specified object into its equivalent Json
* representation. This method should be used when the specified object is not a
* generic type. This method uses {@link Class#getClass()} to get the type for
* the specified object, but the {@code getClass()} loses the generic type
* information because of the Type Erasure feature of Java. Note that this
* method works fine if the any of the object fields are of generic type, just
* the object itself should not be of a generic type. If the object is of
* generic type, use {@link #toJson(Object, Type)} instead. If you want to write
* out the object to a {@link Writer}, use {@link #toJson(Object, Appendable)}
* instead.
*
* @param src
* the object for which Json representation is to be created setting
* for Gson
* @return Json representation of {@code src}.
*/
public String toJson(Object src) {
if (src == null) {
return toJson(JsonNull.INSTANCE);
}
return toJson(src, src.getClass());
}
/**
* This method serializes the specified object, including those of generic
* types, into its equivalent Json representation. This method must be used if
* the specified object is a generic type. For non-generic objects, use
* {@link #toJson(Object)} instead. If you want to write out the object to a
* {@link Appendable}, use {@link #toJson(Object, Type, Appendable)} instead.
*
* @param src
* the object for which JSON representation is to be created
* @param typeOfSrc
* The specific genericized type of src. You can obtain this type by
* using the {@link com.google.gson.reflect.TypeToken} class. For
* example, to get the type for {@code Collection}, you should
* use:
*
*
* Type typeOfSrc = new TypeToken<Collection<Foo>>() {
* }.getType();
*
*
* @return Json representation of {@code src}
*/
public String toJson(Object src, Type typeOfSrc) {
StringWriter writer = new StringWriter();
toJson(src, typeOfSrc, writer);
return writer.toString();
}
/**
* This method serializes the specified object into its equivalent Json
* representation. This method should be used when the specified object is not a
* generic type. This method uses {@link Class#getClass()} to get the type for
* the specified object, but the {@code getClass()} loses the generic type
* information because of the Type Erasure feature of Java. Note that this
* method works fine if the any of the object fields are of generic type, just
* the object itself should not be of a generic type. If the object is of
* generic type, use {@link #toJson(Object, Type, Appendable)} instead.
*
* @param src
* the object for which Json representation is to be created setting
* for Gson
* @param writer
* Writer to which the Json representation needs to be written
* @throws JsonIOException
* if there was a problem writing to the writer
* @since 1.2
*/
public void toJson(Object src, Appendable writer) throws JsonIOException {
if (src != null) {
toJson(src, src.getClass(), writer);
} else {
toJson(JsonNull.INSTANCE, writer);
}
}
/**
* This method serializes the specified object, including those of generic
* types, into its equivalent Json representation. This method must be used if
* the specified object is a generic type. For non-generic objects, use
* {@link #toJson(Object, Appendable)} instead.
*
* @param src
* the object for which JSON representation is to be created
* @param typeOfSrc
* The specific genericized type of src. You can obtain this type by
* using the {@link com.google.gson.reflect.TypeToken} class. For
* example, to get the type for {@code Collection}, you should
* use:
*
*
* Type typeOfSrc = new TypeToken<Collection<Foo>>() {
* }.getType();
*
*
* @param writer
* Writer to which the Json representation of src needs to be
* written.
* @throws JsonIOException
* if there was a problem writing to the writer
* @since 1.2
*/
public void toJson(Object src, Type typeOfSrc, Appendable writer) throws JsonIOException {
try {
JsonWriter jsonWriter = newJsonWriter(Streams.writerForAppendable(writer));
toJson(src, typeOfSrc, jsonWriter);
} catch (IOException e) {
throw new JsonIOException(e);
}
}
/**
* Writes the JSON representation of {@code src} of type {@code typeOfSrc} to
* {@code writer}.
*
* @throws JsonIOException
* if there was a problem writing to the writer
*/
@SuppressWarnings("unchecked")
public void toJson(Object src, Type typeOfSrc, JsonWriter writer) throws JsonIOException {
TypeAdapter> adapter = getAdapter(TypeToken.get(typeOfSrc));
boolean oldLenient = writer.isLenient();
writer.setLenient(true);
boolean oldHtmlSafe = writer.isHtmlSafe();
writer.setHtmlSafe(htmlSafe);
boolean oldSerializeNulls = writer.getSerializeNulls();
writer.setSerializeNulls(serializeNulls);
try {
((TypeAdapter) adapter).write(writer, src);
} catch (IOException e) {
throw new JsonIOException(e);
} finally {
writer.setLenient(oldLenient);
writer.setHtmlSafe(oldHtmlSafe);
writer.setSerializeNulls(oldSerializeNulls);
}
}
/**
* Converts a tree of {@link JsonElement}s into its equivalent JSON
* representation.
*
* @param jsonElement
* root of a tree of {@link JsonElement}s
* @return JSON String representation of the tree
* @since 1.4
*/
public String toJson(JsonElement jsonElement) {
StringWriter writer = new StringWriter();
toJson(jsonElement, writer);
return writer.toString();
}
/**
* Writes out the equivalent JSON for a tree of {@link JsonElement}s.
*
* @param jsonElement
* root of a tree of {@link JsonElement}s
* @param writer
* Writer to which the Json representation needs to be written
* @throws JsonIOException
* if there was a problem writing to the writer
* @since 1.4
*/
public void toJson(JsonElement jsonElement, Appendable writer) throws JsonIOException {
try {
JsonWriter jsonWriter = newJsonWriter(Streams.writerForAppendable(writer));
toJson(jsonElement, jsonWriter);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* Returns a new JSON writer configured for the settings on this Gson instance.
*/
public JsonWriter newJsonWriter(Writer writer) throws IOException {
if (generateNonExecutableJson) {
writer.write(JSON_NON_EXECUTABLE_PREFIX);
}
JsonWriter jsonWriter = new JsonWriter(writer);
if (prettyPrinting) {
jsonWriter.setIndent(" ");
}
jsonWriter.setSerializeNulls(serializeNulls);
return jsonWriter;
}
/**
* Returns a new JSON writer configured for the settings on this Gson instance.
*/
public JsonReader newJsonReader(Reader reader) {
JsonReader jsonReader = new JsonReader(reader);
jsonReader.setLenient(lenient);
return jsonReader;
}
/**
* Writes the JSON for {@code jsonElement} to {@code writer}.
*
* @throws JsonIOException
* if there was a problem writing to the writer
*/
public void toJson(JsonElement jsonElement, JsonWriter writer) throws JsonIOException {
boolean oldLenient = writer.isLenient();
writer.setLenient(true);
boolean oldHtmlSafe = writer.isHtmlSafe();
writer.setHtmlSafe(htmlSafe);
boolean oldSerializeNulls = writer.getSerializeNulls();
writer.setSerializeNulls(serializeNulls);
try {
Streams.write(jsonElement, writer);
} catch (IOException e) {
throw new JsonIOException(e);
} finally {
writer.setLenient(oldLenient);
writer.setHtmlSafe(oldHtmlSafe);
writer.setSerializeNulls(oldSerializeNulls);
}
}
/**
* This method deserializes the specified Json into an object of the specified
* class. It is not suitable to use if the specified class is a generic type
* since it will not have the generic type information because of the Type
* Erasure feature of Java. Therefore, this method should not be used if the
* desired type is a generic type. Note that this method works fine if the any
* of the fields of the specified object are generics, just the object itself
* should not be a generic type. For the cases when the object is of generic
* type, invoke {@link #fromJson(String, Type)}. If you have the Json in a
* {@link Reader} instead of a String, use {@link #fromJson(Reader, Class)}
* instead.
*
* @param
* the type of the desired object
* @param json
* the string from which the object is to be deserialized
* @param classOfT
* the class of T
* @return an object of type T from the string. Returns {@code null} if
* {@code json} is {@code null}.
* @throws JsonSyntaxException
* if json is not a valid representation for an object of type
* classOfT
*/
public T fromJson(String json, Class classOfT) throws JsonSyntaxException {
Object object = fromJson(json, (Type) classOfT);
return Primitives.wrap(classOfT).cast(object);
}
/**
* This method deserializes the specified Json into an object of the specified
* type. This method is useful if the specified object is a generic type. For
* non-generic objects, use {@link #fromJson(String, Class)} instead. If you
* have the Json in a {@link Reader} instead of a String, use
* {@link #fromJson(Reader, Type)} instead.
*
* @param
* the type of the desired object
* @param json
* the string from which the object is to be deserialized
* @param typeOfT
* The specific genericized type of src. You can obtain this type by
* using the {@link com.google.gson.reflect.TypeToken} class. For
* example, to get the type for {@code Collection}, you should
* use:
*
*
* Type typeOfT = new TypeToken<Collection<Foo>>() {
* }.getType();
*
*
* @return an object of type T from the string. Returns {@code null} if
* {@code json} is {@code null}.
* @throws JsonParseException
* if json is not a valid representation for an object of type
* typeOfT
* @throws JsonSyntaxException
* if json is not a valid representation for an object of type
*/
@SuppressWarnings("unchecked")
public T fromJson(String json, Type typeOfT) throws JsonSyntaxException {
if (json == null) {
return null;
}
StringReader reader = new StringReader(json);
T target = (T) fromJson(reader, typeOfT);
return target;
}
/**
* This method deserializes the Json read from the specified reader into an
* object of the specified class. It is not suitable to use if the specified
* class is a generic type since it will not have the generic type information
* because of the Type Erasure feature of Java. Therefore, this method should
* not be used if the desired type is a generic type. Note that this method
* works fine if the any of the fields of the specified object are generics,
* just the object itself should not be a generic type. For the cases when the
* object is of generic type, invoke {@link #fromJson(Reader, Type)}. If you
* have the Json in a String form instead of a {@link Reader}, use
* {@link #fromJson(String, Class)} instead.
*
* @param
* the type of the desired object
* @param json
* the reader producing the Json from which the object is to be
* deserialized.
* @param classOfT
* the class of T
* @return an object of type T from the string. Returns {@code null} if
* {@code json} is at EOF.
* @throws JsonIOException
* if there was a problem reading from the Reader
* @throws JsonSyntaxException
* if json is not a valid representation for an object of type
* @since 1.2
*/
public T fromJson(Reader json, Class classOfT) throws JsonSyntaxException, JsonIOException {
JsonReader jsonReader = newJsonReader(json);
Object object = fromJson(jsonReader, classOfT);
assertFullConsumption(object, jsonReader);
return Primitives.wrap(classOfT).cast(object);
}
/**
* This method deserializes the Json read from the specified reader into an
* object of the specified type. This method is useful if the specified object
* is a generic type. For non-generic objects, use
* {@link #fromJson(Reader, Class)} instead. If you have the Json in a String
* form instead of a {@link Reader}, use {@link #fromJson(String, Type)}
* instead.
*
* @param
* the type of the desired object
* @param json
* the reader producing Json from which the object is to be
* deserialized
* @param typeOfT
* The specific genericized type of src. You can obtain this type by
* using the {@link com.google.gson.reflect.TypeToken} class. For
* example, to get the type for {@code Collection}, you should
* use:
*
*
* Type typeOfT = new TypeToken<Collection<Foo>>() {
* }.getType();
*
*
* @return an object of type T from the json. Returns {@code null} if
* {@code json} is at EOF.
* @throws JsonIOException
* if there was a problem reading from the Reader
* @throws JsonSyntaxException
* if json is not a valid representation for an object of type
* @since 1.2
*/
@SuppressWarnings("unchecked")
public T fromJson(Reader json, Type typeOfT) throws JsonIOException, JsonSyntaxException {
JsonReader jsonReader = newJsonReader(json);
T object = (T) fromJson(jsonReader, typeOfT);
assertFullConsumption(object, jsonReader);
return object;
}
private static void assertFullConsumption(Object obj, JsonReader reader) {
try {
if (obj != null && reader.peek() != JsonToken.END_DOCUMENT) {
throw new JsonIOException("JSON document was not fully consumed.");
}
} catch (MalformedJsonException e) {
throw new JsonSyntaxException(e);
} catch (IOException e) {
throw new JsonIOException(e);
}
}
/**
* Reads the next JSON value from {@code reader} and convert it to an object of
* type {@code typeOfT}. Returns {@code null}, if the {@code reader} is at EOF.
* Since Type is not parameterized by T, this method is type unsafe and should
* be used carefully
*
* @throws JsonIOException
* if there was a problem writing to the Reader
* @throws JsonSyntaxException
* if json is not a valid representation for an object of type
*/
@SuppressWarnings("unchecked")
public T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException {
boolean isEmpty = true;
boolean oldLenient = reader.isLenient();
reader.setLenient(true);
try {
reader.peek();
isEmpty = false;
TypeToken typeToken = (TypeToken) TypeToken.get(typeOfT);
TypeAdapter typeAdapter = getAdapter(typeToken);
T object = typeAdapter.read(reader);
return object;
} catch (EOFException e) {
/*
* For compatibility with JSON 1.5 and earlier, we return null for empty
* documents instead of throwing.
*/
if (isEmpty) {
return null;
}
throw new JsonSyntaxException(e);
} catch (IllegalStateException e) {
throw new JsonSyntaxException(e);
} catch (IOException e) {
// TODO(inder): Figure out whether it is indeed right to rethrow this as
// JsonSyntaxException
throw new JsonSyntaxException(e);
} finally {
reader.setLenient(oldLenient);
}
}
/**
* This method deserializes the Json read from the specified parse tree into an
* object of the specified type. It is not suitable to use if the specified
* class is a generic type since it will not have the generic type information
* because of the Type Erasure feature of Java. Therefore, this method should
* not be used if the desired type is a generic type. Note that this method
* works fine if the any of the fields of the specified object are generics,
* just the object itself should not be a generic type. For the cases when the
* object is of generic type, invoke {@link #fromJson(JsonElement, Type)}.
*
* @param
* the type of the desired object
* @param json
* the root of the parse tree of {@link JsonElement}s from which the
* object is to be deserialized
* @param classOfT
* The class of T
* @return an object of type T from the json. Returns {@code null} if
* {@code json} is {@code null}.
* @throws JsonSyntaxException
* if json is not a valid representation for an object of type
* typeOfT
* @since 1.3
*/
public T fromJson(JsonElement json, Class classOfT) throws JsonSyntaxException {
Object object = fromJson(json, (Type) classOfT);
return Primitives.wrap(classOfT).cast(object);
}
/**
* This method deserializes the Json read from the specified parse tree into an
* object of the specified type. This method is useful if the specified object
* is a generic type. For non-generic objects, use
* {@link #fromJson(JsonElement, Class)} instead.
*
* @param
* the type of the desired object
* @param json
* the root of the parse tree of {@link JsonElement}s from which the
* object is to be deserialized
* @param typeOfT
* The specific genericized type of src. You can obtain this type by
* using the {@link com.google.gson.reflect.TypeToken} class. For
* example, to get the type for {@code Collection}, you should
* use:
*
*
* Type typeOfT = new TypeToken<Collection<Foo>>() {
* }.getType();
*
*
* @return an object of type T from the json. Returns {@code null} if
* {@code json} is {@code null}.
* @throws JsonSyntaxException
* if json is not a valid representation for an object of type
* typeOfT
* @since 1.3
*/
@SuppressWarnings("unchecked")
public T fromJson(JsonElement json, Type typeOfT) throws JsonSyntaxException {
if (json == null) {
return null;
}
return (T) fromJson(new JsonTreeReader(json), typeOfT);
}
static class FutureTypeAdapter extends TypeAdapter {
private TypeAdapter delegate;
public void setDelegate(TypeAdapter typeAdapter) {
if (delegate != null) {
throw new AssertionError();
}
delegate = typeAdapter;
}
@Override
public T read(JsonReader in) throws IOException {
if (delegate == null) {
throw new IllegalStateException();
}
return delegate.read(in);
}
@Override
public void write(JsonWriter out, T value) throws IOException {
if (delegate == null) {
throw new IllegalStateException();
}
delegate.write(out, value);
}
}
@Override
public String toString() {
return new StringBuilder("{serializeNulls:").append(serializeNulls).append("factories:").append(factories).append(",instanceCreators:").append(constructorConstructor).append("}").toString();
}
}