All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.eg.google.gson.Gson Maven / Gradle / Ivy

There is a newer version: 2.1.3
Show newest version
/*
 * 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 com.eg.google.gson;

import com.eg.google.gson.annotations.Expose;
import com.eg.google.gson.annotations.Since;
import com.eg.google.gson.internal.ConstructorConstructor;
import com.eg.google.gson.internal.Excluder;
import com.eg.google.gson.internal.Primitives;
import com.eg.google.gson.internal.Streams;
import com.eg.google.gson.internal.bind.ArrayTypeAdapter;
import com.eg.google.gson.internal.bind.CollectionTypeAdapterFactory;
import com.eg.google.gson.internal.bind.DateTypeAdapter;
import com.eg.google.gson.internal.bind.JsonAdapterAnnotationTypeAdapterFactory;
import com.eg.google.gson.internal.bind.JsonTreeReader;
import com.eg.google.gson.internal.bind.JsonTreeWriter;
import com.eg.google.gson.internal.bind.MapTypeAdapterFactory;
import com.eg.google.gson.internal.bind.ObjectTypeAdapter;
import com.eg.google.gson.internal.bind.ReflectiveTypeAdapterFactory;
import com.eg.google.gson.internal.bind.SqlDateTypeAdapter;
import com.eg.google.gson.internal.bind.TimeTypeAdapter;
import com.eg.google.gson.internal.bind.TypeAdapters;
import com.eg.google.gson.reflect.TypeToken;
import com.eg.google.gson.stream.JsonReader;
import com.eg.google.gson.stream.JsonToken;
import com.eg.google.gson.stream.JsonWriter;
import com.eg.google.gson.stream.MalformedJsonException;

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;


/**
 * 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 deserialing 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 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 BigDecimal}, and {@link 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 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 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 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 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 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 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 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 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(); } } /* package com.google.gson; import ConstructorConstructor; import Excluder; import Primitives; import ArrayTypeAdapter; import CollectionTypeAdapterFactory; import DateTypeAdapter; import JsonTreeReader; import JsonTreeWriter; import MapTypeAdapterFactory; import ObjectTypeAdapter; import ReflectiveTypeAdapterFactory; import SqlDateTypeAdapter; import TimeTypeAdapter; import TypeAdapters; import TypeToken; import JsonReader; import JsonToken; import JsonWriter; import MalformedJsonException; 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 static JsonNull.INSTANCE; import static LongSerializationPolicy.DEFAULT; import static Streams.write; import static Streams.writerForAppendable; import static TypeAdapters.DOUBLE; import static TypeAdapters.FLOAT; import static TypeAdapters.LONG; import static TypeToken.get; import static JsonToken.NULL; import static java.lang.Double.isInfinite; import static java.lang.Double.isNaN; import static java.lang.Float.valueOf; import static java.util.Collections.synchronizedMap; public final class Gson { static final boolean DEFAULT_JSON_NON_EXECUTABLE = false; private static final String JSON_NON_EXECUTABLE_PREFIX = ")]}'\n"; private ThreadLocal, FutureTypeAdapter>> calls = new ThreadLocal(); private Map, TypeAdapter> typeTokenCache = synchronizedMap(new HashMap()); private final List factories; private final ConstructorConstructor constructorConstructor; private final boolean serializeNulls; private final boolean htmlSafe; private final boolean generateNonExecutableJson; private final boolean prettyPrinting; JsonDeserializationContext deserializationContext = new JsonDeserializationContext() { public T deserialize(JsonElement json, Type typeOfT) throws JsonParseException { return (T) Gson.this.fromJson(json, typeOfT); } }; JsonSerializationContext serializationContext = new JsonSerializationContext() { public JsonElement serialize(Object src) { return Gson.this.toJsonTree(src); } public JsonElement serialize(Object src, Type typeOfSrc) { return Gson.this.toJsonTree(src, typeOfSrc); } }; public Gson() { this(Excluder.DEFAULT, FieldNamingPolicy.IDENTITY, Collections.emptyMap(), false, false, false, true, false, false, LongSerializationPolicy.DEFAULT, Collections.emptyList()); } Gson(Excluder excluder, FieldNamingStrategy fieldNamingPolicy, Map> instanceCreators, boolean serializeNulls, boolean complexMapKeySerialization, boolean generateNonExecutableGson, boolean htmlSafe, boolean prettyPrinting, boolean serializeSpecialFloatingPointValues, LongSerializationPolicy longSerializationPolicy, List typeAdapterFactories) { this.calls = new ThreadLocal(); this.typeTokenCache = Collections.synchronizedMap(new HashMap()); this.deserializationContext = new JsonDeserializationContext() { public T deserialize(JsonElement json, Type typeOfT) throws JsonParseException { return Gson.this.fromJson(json, typeOfT); } }; this.serializationContext = new JsonSerializationContext() { public JsonElement serialize(Object src) { return Gson.this.toJsonTree(src); } public JsonElement serialize(Object src, Type typeOfSrc) { return Gson.this.toJsonTree(src, typeOfSrc); } }; this.constructorConstructor = new ConstructorConstructor(instanceCreators); this.serializeNulls = serializeNulls; this.generateNonExecutableJson = generateNonExecutableGson; this.htmlSafe = htmlSafe; this.prettyPrinting = prettyPrinting; ArrayList factories = new ArrayList(); factories.add(TypeAdapters.JSON_ELEMENT_FACTORY); factories.add(ObjectTypeAdapter.FACTORY); factories.add(excluder); factories.addAll(typeAdapterFactories); 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); factories.add(TypeAdapters.newFactory(Long.TYPE, Long.class, this.longAdapter(longSerializationPolicy))); factories.add(TypeAdapters.newFactory(Double.TYPE, Double.class, this.doubleAdapter(serializeSpecialFloatingPointValues))); factories.add(TypeAdapters.newFactory(Float.TYPE, Float.class, this.floatAdapter(serializeSpecialFloatingPointValues))); factories.add(TypeAdapters.NUMBER_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.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.ENUM_FACTORY); factories.add(TypeAdapters.CLASS_FACTORY); factories.add(new CollectionTypeAdapterFactory(this.constructorConstructor)); factories.add(new MapTypeAdapterFactory(this.constructorConstructor, complexMapKeySerialization)); factories.add(new ReflectiveTypeAdapterFactory(this.constructorConstructor, fieldNamingPolicy, excluder)); this.factories = Collections.unmodifiableList(factories); } */ /* public Gson() { this(Excluder.DEFAULT, IDENTITY, emptyMap(), false, false, false, true, false, false, DEFAULT, emptyList()); } *//* */ /*Gson(Excluder excluder, FieldNamingStrategy fieldNamingPolicy, Map> instanceCreators, boolean serializeNulls, boolean complexMapKeySerialization, boolean generateNonExecutableGson, boolean htmlSafe, boolean prettyPrinting, boolean serializeSpecialFloatingPointValues, LongSerializationPolicy longSerializationPolicy, List typeAdapterFactories) { this.constructorConstructor = new ConstructorConstructor(instanceCreators); this.serializeNulls = serializeNulls; this.generateNonExecutableJson = generateNonExecutableGson; this.htmlSafe = htmlSafe; this.prettyPrinting = prettyPrinting; List factories = new ArrayList(); factories.add(JSON_ELEMENT_FACTORY); factories.add(FACTORY); factories.add(excluder); factories.addAll(typeAdapterFactories); factories.add(STRING_FACTORY); factories.add(INTEGER_FACTORY); factories.add(BOOLEAN_FACTORY); factories.add(BYTE_FACTORY); factories.add(SHORT_FACTORY); factories.add(newFactory(TYPE, Long.class, longAdapter(longSerializationPolicy))); factories.add(newFactory(Double.TYPE, Double.class, doubleAdapter(serializeSpecialFloatingPointValues))); factories.add(newFactory(Float.TYPE, Float.class, floatAdapter(serializeSpecialFloatingPointValues))); factories.add(NUMBER_FACTORY); factories.add(CHARACTER_FACTORY); factories.add(STRING_BUILDER_FACTORY); factories.add(STRING_BUFFER_FACTORY); factories.add(newFactory(BigDecimal.class, BIG_DECIMAL)); factories.add(newFactory(BigInteger.class, BIG_INTEGER)); factories.add(URL_FACTORY); factories.add(URI_FACTORY); factories.add(UUID_FACTORY); factories.add(LOCALE_FACTORY); factories.add(INET_ADDRESS_FACTORY); factories.add(BIT_SET_FACTORY); factories.add(DateTypeAdapter.FACTORY); factories.add(CALENDAR_FACTORY); factories.add(TimeTypeAdapter.FACTORY); factories.add(SqlDateTypeAdapter.FACTORY); factories.add(TIMESTAMP_FACTORY); factories.add(ArrayTypeAdapter.FACTORY); factories.add(ENUM_FACTORY); factories.add(CLASS_FACTORY); factories.add(new CollectionTypeAdapterFactory(this.constructorConstructor)); factories.add(new MapTypeAdapterFactory(this.constructorConstructor, complexMapKeySerialization)); factories.add(new ReflectiveTypeAdapterFactory(this.constructorConstructor, fieldNamingPolicy, excluder)); this.factories = unmodifiableList(factories); }*//* private TypeAdapter doubleAdapter(boolean serializeSpecialFloatingPointValues) { if (serializeSpecialFloatingPointValues) { return DOUBLE; } new TypeAdapter() { public Double read(JsonReader in) throws IOException { if (in.peek() == NULL) { in.nextNull(); return null; } return Double.valueOf(in.nextDouble()); } public void write(JsonWriter out, Number value) throws IOException { if (value == null) { out.nullValue(); return; } double doubleValue = value.doubleValue(); Gson.this.checkValidFloatingPoint(doubleValue); out.value(value); } }; return null; } private TypeAdapter floatAdapter(boolean serializeSpecialFloatingPointValues) { if (serializeSpecialFloatingPointValues) { return FLOAT; } new TypeAdapter() { public Float read(JsonReader in) throws IOException { if (in.peek() == NULL) { in.nextNull(); return null; } return valueOf((float) in.nextDouble()); } public void write(JsonWriter out, Number value) throws IOException { if (value == null) { out.nullValue(); return; } float floatValue = value.floatValue(); Gson.this.checkValidFloatingPoint(floatValue); out.value(value); } }; return null; } private void checkValidFloatingPoint(double value) { if ((isNaN(value)) || (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 TypeAdapter longAdapter(LongSerializationPolicy longSerializationPolicy) { if (longSerializationPolicy == DEFAULT) { return LONG; } new TypeAdapter() { public Number read(JsonReader in) throws IOException { if (in.peek() == NULL) { in.nextNull(); return null; } return Long.valueOf(in.nextLong()); } public void write(JsonWriter out, Number value) throws IOException { if (value == null) { out.nullValue(); return; } out.value(value.toString()); } }; return null; } public TypeAdapter getAdapter(TypeToken type) { TypeAdapter cached = (TypeAdapter) this.typeTokenCache.get(type); if (cached != null) { return cached; } Map, FutureTypeAdapter> threadCalls = (Map) this.calls.get(); boolean requiresThreadLocalCleanup = false; if (threadCalls == null) { threadCalls = new HashMap(); this.calls.set(threadCalls); requiresThreadLocalCleanup = true; } FutureTypeAdapter ongoingCall = (FutureTypeAdapter) threadCalls.get(type); if (ongoingCall != null) { return ongoingCall; } try { FutureTypeAdapter call = new FutureTypeAdapter(); threadCalls.put(type, call); for (TypeAdapterFactory factory : this.factories) { TypeAdapter candidate = factory.create(this, type); if (candidate != null) { call.setDelegate(candidate); this.typeTokenCache.put(type, candidate); return candidate; } } throw new IllegalArgumentException("GSON cannot handle " + type); } finally { threadCalls.remove(type); if (requiresThreadLocalCleanup) { this.calls.remove(); } } } public TypeAdapter getDelegateAdapter(TypeAdapterFactory skipPast, TypeToken type) { boolean skipPastFound = false; for (TypeAdapterFactory factory : this.factories) { if (!skipPastFound) { if (factory == skipPast) { skipPastFound = true; } } else { TypeAdapter candidate = factory.create(this, type); if (candidate != null) return candidate; } } throw new IllegalArgumentException("GSON cannot serialize " + type); } public TypeAdapter getAdapter(Class type) { return getAdapter(get(type)); } public JsonElement toJsonTree(Object src) { if (src == null) { return INSTANCE; } return toJsonTree(src, src.getClass()); } public JsonElement toJsonTree(Object src, Type typeOfSrc) { JsonTreeWriter writer = new JsonTreeWriter(); toJson(src, typeOfSrc, writer); return writer.get(); } public String toJson(Object src) { if (src == null) { return toJson(INSTANCE); } return toJson(src, src.getClass()); } public String toJson(Object src, Type typeOfSrc) { StringWriter writer = new StringWriter(); toJson(src, typeOfSrc, writer); return writer.toString(); } public void toJson(Object src, Appendable writer) throws JsonIOException { if (src != null) { toJson(src, src.getClass(), writer); } else { toJson(INSTANCE, writer); } } public void toJson(Object src, Type typeOfSrc, Appendable writer) throws JsonIOException { try { JsonWriter jsonWriter = newJsonWriter(writerForAppendable(writer)); toJson(src, typeOfSrc, jsonWriter); } catch (IOException e) { throw new JsonIOException(e); } } public void toJson(Object src, Type typeOfSrc, JsonWriter writer) throws JsonIOException { TypeAdapter adapter = getAdapter(get(typeOfSrc)); boolean oldLenient = writer.isLenient(); writer.setLenient(true); boolean oldHtmlSafe = writer.isHtmlSafe(); writer.setHtmlSafe(this.htmlSafe); boolean oldSerializeNulls = writer.getSerializeNulls(); writer.setSerializeNulls(this.serializeNulls); try { // adapter.write(writer, src); ((TypeAdapter) adapter).write(writer, src); } catch (IOException e) { throw new JsonIOException(e); } finally { writer.setLenient(oldLenient); writer.setHtmlSafe(oldHtmlSafe); writer.setSerializeNulls(oldSerializeNulls); } } public String toJson(JsonElement jsonElement) { StringWriter writer = new StringWriter(); toJson(jsonElement, writer); return writer.toString(); } public void toJson(JsonElement jsonElement, Appendable writer) throws JsonIOException { try { JsonWriter jsonWriter = newJsonWriter(writerForAppendable(writer)); toJson(jsonElement, jsonWriter); } catch (IOException e) { throw new RuntimeException(e); } } private JsonWriter newJsonWriter(Writer writer) throws IOException { if (this.generateNonExecutableJson) { writer.write(")]}'\n"); } JsonWriter jsonWriter = new JsonWriter(writer); if (this.prettyPrinting) { jsonWriter.setIndent(" "); } jsonWriter.setSerializeNulls(this.serializeNulls); return jsonWriter; } public void toJson(JsonElement jsonElement, JsonWriter writer) throws JsonIOException { boolean oldLenient = writer.isLenient(); writer.setLenient(true); boolean oldHtmlSafe = writer.isHtmlSafe(); writer.setHtmlSafe(this.htmlSafe); boolean oldSerializeNulls = writer.getSerializeNulls(); writer.setSerializeNulls(this.serializeNulls); try { write(jsonElement, writer); } catch (IOException e) { throw new JsonIOException(e); } finally { writer.setLenient(oldLenient); writer.setHtmlSafe(oldHtmlSafe); writer.setSerializeNulls(oldSerializeNulls); } } public T fromJson(String json, Class classOfT) throws JsonSyntaxException { Object object = fromJson(json, classOfT); return (T)Primitives.wrap(classOfT).cast(object); } public T fromJson(String json, Type typeOfT) throws JsonSyntaxException { if (json == null) { return null; } StringReader reader = new StringReader(json); T target = fromJson(reader, typeOfT); return target; } public T fromJson(Reader json, Class classOfT) throws JsonSyntaxException, JsonIOException { JsonReader jsonReader = new JsonReader(json); Object object = fromJson(jsonReader, classOfT); assertFullConsumption(object, jsonReader); return (T)Primitives.wrap(classOfT).cast(object); } public T fromJson(Reader json, Type typeOfT) throws JsonIOException, JsonSyntaxException { JsonReader jsonReader = new JsonReader(json); T object = 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); } } 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); } } public T fromJson(JsonElement json, Class classOfT) throws JsonSyntaxException { Object object = fromJson(json, classOfT); return (T)Primitives.wrap(classOfT).cast(object); } 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 (this.delegate != null) { throw new AssertionError(); } this.delegate = typeAdapter; } public T read(JsonReader in) throws IOException { if (this.delegate == null) { throw new IllegalStateException(); } return (T)this.delegate.read(in); } public void write(JsonWriter out, T value) throws IOException { if (this.delegate == null) { throw new IllegalStateException(); } this.delegate.write(out, value); } } public String toString() { return "{serializeNulls:" + this.serializeNulls + "factories:" + this.factories + ",instanceCreators:" + this.constructorConstructor + "}"; } } */