/* * 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.google.gson; import static com.google.gson.GsonBuilder.newImmutableList; import com.google.gson.annotations.JsonAdapter; import com.google.gson.internal.ConstructorConstructor; import com.google.gson.internal.Excluder; import com.google.gson.internal.GsonBuildConfig; import com.google.gson.internal.Primitives; import com.google.gson.internal.Streams; import com.google.gson.internal.bind.JsonAdapterAnnotationTypeAdapterFactory; import com.google.gson.internal.bind.JsonTreeReader; import com.google.gson.internal.bind.JsonTreeWriter; import com.google.gson.internal.bind.SerializationDelegatingTypeAdapter; import com.google.gson.reflect.TypeToken; import com.google.gson.stream.JsonReader; import com.google.gson.stream.JsonToken; import com.google.gson.stream.JsonWriter; import com.google.gson.stream.MalformedJsonException; import java.io.EOFException; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.io.Writer; import java.lang.reflect.Type; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; /** * 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 newline, custom indent, * 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 type of the object that you are converting is a {@code ParameterizedType} (i.e. has at * least one type argument, for example {@code List}) then for deserialization you must use * a {@code fromJson} method with {@link Type} or {@link TypeToken} parameter to specify the * parameterized type. For serialization specifying a {@code Type} or {@code TypeToken} is optional, * otherwise Gson will use the runtime type of the object. {@link TypeToken} is a class provided by * Gson which helps creating parameterized types. Here is an example showing how this can be done: * *

 * TypeToken<List<MyType>> listType = new TypeToken<List<MyType>>() {};
 * List<MyType> target = new LinkedList<MyType>();
 * target.add(new MyType(1, "abc"));
 *
 * Gson gson = new Gson();
 * // For serialization you normally do not have to specify the type, Gson will use
 * // the runtime type of the objects, however you can also specify it explicitly
 * String json = gson.toJson(target, listType.getType());
 *
 * // But for deserialization you have to specify the type
 * List<MyType> target2 = gson.fromJson(json, listType);
 * 
* *

See the Gson User Guide * for a more complete set of examples. * *

JSON Strictness handling

* * For legacy reasons most of the {@code Gson} methods allow JSON data which does not comply with * the JSON specification when no explicit {@linkplain Strictness strictness} is set (the default). * To specify the strictness of a {@code Gson} instance, you should set it through {@link * GsonBuilder#setStrictness(Strictness)}. * *

For older Gson versions, which don't have the strictness mode API, the following workarounds * can be used: * *

Serialization

* *
    *
  1. Use {@link #getAdapter(Class)} to obtain the adapter for the type to be serialized *
  2. When using an existing {@code JsonWriter}, manually apply the writer settings of this * {@code Gson} instance listed by {@link #newJsonWriter(Writer)}.
    * Otherwise, when not using an existing {@code JsonWriter}, use {@link * #newJsonWriter(Writer)} to construct one. *
  3. Call {@link TypeAdapter#write(JsonWriter, Object)} *
* *

Deserialization

* *
    *
  1. Use {@link #getAdapter(Class)} to obtain the adapter for the type to be deserialized *
  2. When using an existing {@code JsonReader}, manually apply the reader settings of this * {@code Gson} instance listed by {@link #newJsonReader(Reader)}.
    * Otherwise, when not using an existing {@code JsonReader}, use {@link * #newJsonReader(Reader)} to construct one. *
  3. Call {@link TypeAdapter#read(JsonReader)} *
  4. Call {@link JsonReader#peek()} and verify that the result is {@link JsonToken#END_DOCUMENT} * to make sure there is no trailing data *
* * Note that the {@code JsonReader} created this way is only 'legacy strict', it mostly adheres to * the JSON specification but allows small deviations. See {@link * JsonReader#setStrictness(Strictness)} for details. * * @see TypeToken * @author Inderjeet Singh * @author Joel Leitch * @author Jesse Wilson */ public final class Gson { private static final String JSON_NON_EXECUTABLE_PREFIX = ")]}'\n"; /** * This thread local guards against reentrant calls to {@link #getAdapter(TypeToken)}. 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, {@link FutureTypeAdapter}, which is wired up once the initial adapter has * been created. * *

The map stores the type adapters for ongoing {@code getAdapter} calls, with the type token * provided to {@code getAdapter} as key and either {@code FutureTypeAdapter} or a regular {@code * TypeAdapter} as value. */ @SuppressWarnings("ThreadLocalUsage") private final ThreadLocal, TypeAdapter>> threadLocalAdapterResults = new ThreadLocal<>(); private final ConcurrentMap, TypeAdapter> typeTokenCache = new ConcurrentHashMap<>(); private final ConstructorConstructor constructorConstructor; private final JsonAdapterAnnotationTypeAdapterFactory jsonAdapterFactory; final List factories; final Excluder excluder; final FieldNamingStrategy fieldNamingStrategy; final Map> instanceCreators; final boolean serializeNulls; final boolean complexMapKeySerialization; final boolean generateNonExecutableJson; final boolean htmlSafe; final FormattingStyle formattingStyle; final Strictness strictness; final boolean serializeSpecialFloatingPointValues; final boolean useJdkUnsafe; final String datePattern; final int dateStyle; final int timeStyle; final LongSerializationPolicy longSerializationPolicy; final List builderFactories; final List builderHierarchyFactories; final ToNumberStrategy objectToNumberStrategy; final ToNumberStrategy numberToNumberStrategy; final List reflectionFilters; /** * Constructs a Gson object with default configuration. The default configuration has the * following settings: * *

*/ public Gson() { this(GsonBuilder.DEFAULT); } Gson(GsonBuilder builder) { this.excluder = builder.excluder; this.fieldNamingStrategy = builder.fieldNamingPolicy; this.instanceCreators = new HashMap<>(builder.instanceCreators); this.serializeNulls = builder.serializeNulls; this.complexMapKeySerialization = builder.complexMapKeySerialization; this.generateNonExecutableJson = builder.generateNonExecutableJson; this.htmlSafe = builder.escapeHtmlChars; this.formattingStyle = builder.formattingStyle; this.strictness = builder.strictness; this.serializeSpecialFloatingPointValues = builder.serializeSpecialFloatingPointValues; this.useJdkUnsafe = builder.useJdkUnsafe; this.longSerializationPolicy = builder.longSerializationPolicy; this.datePattern = builder.datePattern; this.dateStyle = builder.dateStyle; this.timeStyle = builder.timeStyle; this.builderFactories = newImmutableList(builder.factories); this.builderHierarchyFactories = newImmutableList(builder.hierarchyFactories); this.objectToNumberStrategy = builder.objectToNumberStrategy; this.numberToNumberStrategy = builder.numberToNumberStrategy; this.reflectionFilters = newImmutableList(builder.reflectionFilters); if (builder == GsonBuilder.DEFAULT) { this.constructorConstructor = GsonBuilder.DEFAULT_CONSTRUCTOR_CONSTRUCTOR; this.jsonAdapterFactory = GsonBuilder.DEFAULT_JSON_ADAPTER_ANNOTATION_TYPE_ADAPTER_FACTORY; this.factories = GsonBuilder.DEFAULT_TYPE_ADAPTER_FACTORIES; } else { this.constructorConstructor = new ConstructorConstructor(instanceCreators, useJdkUnsafe, reflectionFilters); this.jsonAdapterFactory = new JsonAdapterAnnotationTypeAdapterFactory(constructorConstructor); this.factories = builder.createFactories(constructorConstructor, jsonAdapterFactory); } } /** * Returns a new GsonBuilder containing all custom factories and configuration used by the current * instance. * * @return a GsonBuilder instance. * @since 2.8.3 */ public GsonBuilder newBuilder() { return new GsonBuilder(this); } /** * @deprecated This method by accident exposes an internal Gson class; it might be removed in a * future version. */ @Deprecated public Excluder excluder() { return excluder; } /** * Returns the field naming strategy used by this Gson instance. * * @see GsonBuilder#setFieldNamingStrategy(FieldNamingStrategy) */ public FieldNamingStrategy fieldNamingStrategy() { return fieldNamingStrategy; } /** * Returns whether this Gson instance is serializing JSON object properties with {@code null} * values, or just omits them. * * @see GsonBuilder#serializeNulls() */ public boolean serializeNulls() { return serializeNulls; } /** * Returns whether this Gson instance produces JSON output which is HTML-safe, that means all HTML * characters are escaped. * * @see GsonBuilder#disableHtmlEscaping() */ public boolean htmlSafe() { return htmlSafe; } /** * Returns the type adapter for {@code type}. * *

When calling this method concurrently from multiple threads and requesting an adapter for * the same type this method may return different {@code TypeAdapter} instances. However, that * should normally not be an issue because {@code TypeAdapter} implementations are supposed to be * stateless. * * @throws IllegalArgumentException if this Gson instance cannot serialize and deserialize {@code * type}. */ public TypeAdapter getAdapter(TypeToken type) { Objects.requireNonNull(type, "type must not be null"); TypeAdapter cached = typeTokenCache.get(type); if (cached != null) { @SuppressWarnings("unchecked") TypeAdapter adapter = (TypeAdapter) cached; return adapter; } Map, TypeAdapter> threadCalls = threadLocalAdapterResults.get(); boolean isInitialAdapterRequest = false; if (threadCalls == null) { threadCalls = new HashMap<>(); threadLocalAdapterResults.set(threadCalls); isInitialAdapterRequest = true; } else { // the key and value type parameters always agree @SuppressWarnings("unchecked") TypeAdapter ongoingCall = (TypeAdapter) threadCalls.get(type); if (ongoingCall != null) { return ongoingCall; } } TypeAdapter candidate = null; try { FutureTypeAdapter call = new FutureTypeAdapter<>(); threadCalls.put(type, call); for (TypeAdapterFactory factory : factories) { candidate = factory.create(this, type); if (candidate != null) { call.setDelegate(candidate); // Replace future adapter with actual adapter threadCalls.put(type, candidate); break; } } } finally { if (isInitialAdapterRequest) { threadLocalAdapterResults.remove(); } } if (candidate == null) { throw new IllegalArgumentException( "GSON (" + GsonBuildConfig.VERSION + ") cannot handle " + type); } if (isInitialAdapterRequest) { /* * Publish resolved adapters to all threads * Can only do this for the initial request because cyclic dependency TypeA -> TypeB -> TypeA * would otherwise publish adapter for TypeB which uses not yet resolved adapter for TypeA * See https://github.com/google/gson/issues/625 */ typeTokenCache.putAll(threadCalls); } return candidate; } /** * Returns the type adapter for {@code type}. * * @throws IllegalArgumentException if this Gson instance cannot serialize and deserialize {@code * type}. */ public TypeAdapter getAdapter(Class type) { return getAdapter(TypeToken.get(type)); } /** * 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 feature 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 {@code * getDelegateAdapter} method: * *

{@code
   * class StatsTypeAdapterFactory implements TypeAdapterFactory {
   *   public int numReads = 0;
   *   public int numWrites = 0;
   *   public  TypeAdapter create(Gson gson, TypeToken type) {
   *     TypeAdapter delegate = gson.getDelegateAdapter(this, type);
   *     return new TypeAdapter() {
   *       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 ensure 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 the type adapter factories * for some types, see {@link GsonBuilder#registerTypeAdapter(Type, Object)}, our stats factory * will not count the number of instances of those types that will be read or written. * *

If {@code skipPast} is a factory which has neither been registered on the {@link * GsonBuilder} nor specified with the {@link JsonAdapter @JsonAdapter} annotation on a class, * then this method behaves as if {@link #getAdapter(TypeToken)} had been called. This also means * that for fields with {@code @JsonAdapter} annotation this method behaves normally like {@code * getAdapter} (except for corner cases where a custom {@link InstanceCreator} is used to create * an instance of the factory). * * @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 {@code 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) { Objects.requireNonNull(skipPast, "skipPast must not be null"); Objects.requireNonNull(type, "type must not be null"); if (jsonAdapterFactory.isClassJsonAdapterFactory(type, skipPast)) { skipPast = jsonAdapterFactory; } boolean skipPastFound = false; for (TypeAdapterFactory factory : factories) { if (!skipPastFound) { if (factory == skipPast) { skipPastFound = true; } continue; } TypeAdapter candidate = factory.create(this, type); if (candidate != null) { return candidate; } } if (skipPastFound) { throw new IllegalArgumentException("GSON cannot serialize or deserialize " + type); } else { // Probably a factory from @JsonAdapter on a field return getAdapter(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 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 * @return JSON representation of {@code src}. * @since 1.4 * @see #toJsonTree(Object, Type) */ 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 * @see #toJsonTree(Object) */ 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 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 * @return JSON representation of {@code src}. * @see #toJson(Object, Appendable) * @see #toJson(Object, Type) */ 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}. * @see #toJson(Object, Type, Appendable) * @see #toJson(Object) */ public String toJson(Object src, Type typeOfSrc) { StringBuilder writer = new StringBuilder(); toJson(src, typeOfSrc, writer); return writer.toString(); } /** * This method serializes the specified object into its equivalent JSON representation and writes * it to the writer. 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 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 * @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 * @see #toJson(Object) * @see #toJson(Object, Type, Appendable) */ 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 and writes it to the writer. 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 * @see #toJson(Object, Type) * @see #toJson(Object, Appendable) */ 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}. * *

If the {@code Gson} instance has an {@linkplain GsonBuilder#setStrictness(Strictness) * explicit strictness setting}, this setting will be used for writing the JSON regardless of the * {@linkplain JsonWriter#getStrictness() strictness} of the provided {@link JsonWriter}. For * legacy reasons, if the {@code Gson} instance has no explicit strictness setting and the writer * does not have the strictness {@link Strictness#STRICT}, the JSON will be written in {@link * Strictness#LENIENT} mode.
* Note that in all cases the old strictness setting of the writer will be restored when this * method returns. * *

The 'HTML-safe' and 'serialize {@code null}' settings of this {@code Gson} instance * (configured by the {@link GsonBuilder}) are applied, and the original settings of the writer * are restored once this method returns. * * @param src the object for which JSON representation is to be created * @param typeOfSrc the type of the object to be written * @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 */ public void toJson(Object src, Type typeOfSrc, JsonWriter writer) throws JsonIOException { @SuppressWarnings("unchecked") TypeAdapter adapter = (TypeAdapter) getAdapter(TypeToken.get(typeOfSrc)); Strictness oldStrictness = writer.getStrictness(); if (this.strictness != null) { writer.setStrictness(this.strictness); } else if (writer.getStrictness() == Strictness.LEGACY_STRICT) { // For backward compatibility change to LENIENT if writer has default strictness LEGACY_STRICT writer.setStrictness(Strictness.LENIENT); } boolean oldHtmlSafe = writer.isHtmlSafe(); boolean oldSerializeNulls = writer.getSerializeNulls(); writer.setHtmlSafe(htmlSafe); writer.setSerializeNulls(serializeNulls); try { adapter.write(writer, src); } catch (IOException e) { throw new JsonIOException(e); } catch (AssertionError e) { throw new AssertionError( "AssertionError (GSON " + GsonBuildConfig.VERSION + "): " + e.getMessage(), e); } finally { writer.setStrictness(oldStrictness); 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) { StringBuilder writer = new StringBuilder(); 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 JsonIOException(e); } } /** * Writes the JSON for {@code jsonElement} to {@code writer}. * *

If the {@code Gson} instance has an {@linkplain GsonBuilder#setStrictness(Strictness) * explicit strictness setting}, this setting will be used for writing the JSON regardless of the * {@linkplain JsonWriter#getStrictness() strictness} of the provided {@link JsonWriter}. For * legacy reasons, if the {@code Gson} instance has no explicit strictness setting and the writer * does not have the strictness {@link Strictness#STRICT}, the JSON will be written in {@link * Strictness#LENIENT} mode.
* Note that in all cases the old strictness setting of the writer will be restored when this * method returns. * *

The 'HTML-safe' and 'serialize {@code null}' settings of this {@code Gson} instance * (configured by the {@link GsonBuilder}) are applied, and the original settings of the writer * are restored once this method returns. * * @param jsonElement the JSON element to be written * @param writer the JSON writer to which the provided element will be written * @throws JsonIOException if there was a problem writing to the writer */ public void toJson(JsonElement jsonElement, JsonWriter writer) throws JsonIOException { Strictness oldStrictness = writer.getStrictness(); boolean oldHtmlSafe = writer.isHtmlSafe(); boolean oldSerializeNulls = writer.getSerializeNulls(); writer.setHtmlSafe(htmlSafe); writer.setSerializeNulls(serializeNulls); if (this.strictness != null) { writer.setStrictness(this.strictness); } else if (writer.getStrictness() == Strictness.LEGACY_STRICT) { // For backward compatibility change to LENIENT if writer has default strictness LEGACY_STRICT writer.setStrictness(Strictness.LENIENT); } try { Streams.write(jsonElement, writer); } catch (IOException e) { throw new JsonIOException(e); } catch (AssertionError e) { throw new AssertionError( "AssertionError (GSON " + GsonBuildConfig.VERSION + "): " + e.getMessage(), e); } finally { writer.setStrictness(oldStrictness); writer.setHtmlSafe(oldHtmlSafe); writer.setSerializeNulls(oldSerializeNulls); } } /** * Returns a new JSON writer configured for the settings on this Gson instance. * *

The following settings are considered: * *

    *
  • {@link GsonBuilder#disableHtmlEscaping()} *
  • {@link GsonBuilder#generateNonExecutableJson()} *
  • {@link GsonBuilder#serializeNulls()} *
  • {@link GsonBuilder#setStrictness(Strictness)}. If no {@linkplain * GsonBuilder#setStrictness(Strictness) explicit strictness has been set} the created * writer will have a strictness of {@link Strictness#LEGACY_STRICT}. Otherwise, the * strictness of the {@code Gson} instance will be used for the created writer. *
  • {@link GsonBuilder#setPrettyPrinting()} *
  • {@link GsonBuilder#setFormattingStyle(FormattingStyle)} *
*/ public JsonWriter newJsonWriter(Writer writer) throws IOException { if (generateNonExecutableJson) { writer.write(JSON_NON_EXECUTABLE_PREFIX); } JsonWriter jsonWriter = new JsonWriter(writer); jsonWriter.setFormattingStyle(formattingStyle); jsonWriter.setHtmlSafe(htmlSafe); jsonWriter.setStrictness(strictness == null ? Strictness.LEGACY_STRICT : strictness); jsonWriter.setSerializeNulls(serializeNulls); return jsonWriter; } /** * Returns a new JSON reader configured for the settings on this Gson instance. * *

The following settings are considered: * *

    *
  • {@link GsonBuilder#setStrictness(Strictness)}. If no {@linkplain * GsonBuilder#setStrictness(Strictness) explicit strictness has been set} the created * reader will have a strictness of {@link Strictness#LEGACY_STRICT}. Otherwise, the * strictness of the {@code Gson} instance will be used for the created reader. *
*/ public JsonReader newJsonReader(Reader reader) { JsonReader jsonReader = new JsonReader(reader); jsonReader.setStrictness(strictness == null ? Strictness.LEGACY_STRICT : strictness); return jsonReader; } /** * 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 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, * TypeToken)}. If you have the JSON in a {@link Reader} instead of a String, use {@link * #fromJson(Reader, Class)} instead. * *

An exception is thrown if the JSON string has multiple top-level JSON elements, or if there * is trailing data. Use {@link #fromJson(JsonReader, Type)} if this behavior is not desired. * * @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} or if {@code json} is empty. * @throws JsonSyntaxException if json is not a valid representation for an object of type * classOfT * @see #fromJson(Reader, Class) * @see #fromJson(String, TypeToken) */ public T fromJson(String json, Class classOfT) throws JsonSyntaxException { return fromJson(json, TypeToken.get(classOfT)); } /** * 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. * *

Since {@code Type} is not parameterized by T, this method is not type-safe and should be * used carefully. If you are creating the {@code Type} from a {@link TypeToken}, prefer using * {@link #fromJson(String, TypeToken)} instead since its return type is based on the {@code * TypeToken} and is therefore more type-safe. * *

An exception is thrown if the JSON string has multiple top-level JSON elements, or if there * is trailing data. Use {@link #fromJson(JsonReader, Type)} if this behavior is not desired. * * @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 * @return an object of type T from the string. Returns {@code null} if {@code json} is {@code * null} or if {@code json} is empty. * @throws JsonSyntaxException if json is not a valid representation for an object of type typeOfT * @see #fromJson(Reader, Type) * @see #fromJson(String, Class) * @see #fromJson(String, TypeToken) */ @SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"}) public T fromJson(String json, Type typeOfT) throws JsonSyntaxException { return (T) fromJson(json, TypeToken.get(typeOfT)); } /** * 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, TypeToken)} instead. * *

An exception is thrown if the JSON string has multiple top-level JSON elements, or if there * is trailing data. Use {@link #fromJson(JsonReader, TypeToken)} if this behavior is not desired. * * @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 should create an anonymous subclass of * {@code TypeToken} with the specific generic type arguments. For example, to get the type * for {@code Collection}, you should use: *

   * new TypeToken<Collection<Foo>>(){}
   * 
* * @return an object of type T from the string. Returns {@code null} if {@code json} is {@code * null} or if {@code json} is empty. * @throws JsonSyntaxException if json is not a valid representation for an object of the type * typeOfT * @see #fromJson(Reader, TypeToken) * @see #fromJson(String, Class) * @since 2.10 */ public T fromJson(String json, TypeToken typeOfT) throws JsonSyntaxException { if (json == null) { return null; } StringReader reader = new StringReader(json); return fromJson(reader, typeOfT); } /** * 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 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, TypeToken)}. If you have the JSON in a String form instead of a {@link * Reader}, use {@link #fromJson(String, Class)} instead. * *

An exception is thrown if the JSON data has multiple top-level JSON elements, or if there is * trailing data. Use {@link #fromJson(JsonReader, Type)} if this behavior is not desired. * * @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 Reader. 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 typeOfT * @since 1.2 * @see #fromJson(String, Class) * @see #fromJson(Reader, TypeToken) */ public T fromJson(Reader json, Class classOfT) throws JsonSyntaxException, JsonIOException { return fromJson(json, TypeToken.get(classOfT)); } /** * 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. * *

Since {@code Type} is not parameterized by T, this method is not type-safe and should be * used carefully. If you are creating the {@code Type} from a {@link TypeToken}, prefer using * {@link #fromJson(Reader, TypeToken)} instead since its return type is based on the {@code * TypeToken} and is therefore more type-safe. * *

An exception is thrown if the JSON data has multiple top-level JSON elements, or if there is * trailing data. Use {@link #fromJson(JsonReader, Type)} if this behavior is not desired. * * @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 * @return an object of type T from the Reader. 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 typeOfT * @since 1.2 * @see #fromJson(String, Type) * @see #fromJson(Reader, Class) * @see #fromJson(Reader, TypeToken) */ @SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"}) public T fromJson(Reader json, Type typeOfT) throws JsonIOException, JsonSyntaxException { return (T) fromJson(json, TypeToken.get(typeOfT)); } /** * 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, TypeToken)} instead. * *

An exception is thrown if the JSON data has multiple top-level JSON elements, or if there is * trailing data. Use {@link #fromJson(JsonReader, TypeToken)} if this behavior is not desired. * * @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 should create an anonymous subclass of * {@code TypeToken} with the specific generic type arguments. For example, to get the type * for {@code Collection}, you should use: *

   * new TypeToken<Collection<Foo>>(){}
   * 
* * @return an object of type T from the Reader. 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 of * typeOfT * @see #fromJson(String, TypeToken) * @see #fromJson(Reader, Class) * @since 2.10 */ public T fromJson(Reader json, TypeToken typeOfT) throws JsonIOException, JsonSyntaxException { JsonReader jsonReader = newJsonReader(json); T object = fromJson(jsonReader, typeOfT); assertFullConsumption(object, jsonReader); return object; } // fromJson(JsonReader, Class) is unfortunately missing and cannot be added now without breaking // source compatibility in certain cases, see // https://github.com/google/gson/pull/1700#discussion_r973764414 /** * Reads the next JSON value from {@code reader} and converts it to an object of type {@code * typeOfT}. Returns {@code null}, if the {@code reader} is at EOF. * *

Since {@code Type} is not parameterized by T, this method is not type-safe and should be * used carefully. If you are creating the {@code Type} from a {@link TypeToken}, prefer using * {@link #fromJson(JsonReader, TypeToken)} instead since its return type is based on the {@code * TypeToken} and is therefore more type-safe. If the provided type is a {@code Class} the {@code * TypeToken} can be created with {@link TypeToken#get(Class)}. * *

Unlike the other {@code fromJson} methods, no exception is thrown if the JSON data has * multiple top-level JSON elements, or if there is trailing data. * *

If the {@code Gson} instance has an {@linkplain GsonBuilder#setStrictness(Strictness) * explicit strictness setting}, this setting will be used for reading the JSON regardless of the * {@linkplain JsonReader#getStrictness() strictness} of the provided {@link JsonReader}. For * legacy reasons, if the {@code Gson} instance has no explicit strictness setting and the reader * does not have the strictness {@link Strictness#STRICT}, the JSON will be written in {@link * Strictness#LENIENT} mode.
* Note that in all cases the old strictness setting of the reader will be restored when this * method returns. * * @param the type of the desired object * @param reader the reader whose next JSON value should be deserialized * @param typeOfT The specific genericized type of src * @return an object of type T from the JsonReader. Returns {@code null} if {@code reader} is at * EOF. * @throws JsonIOException if there was a problem reading from the JsonReader * @throws JsonSyntaxException if json is not a valid representation for an object of type typeOfT * @see #fromJson(Reader, Type) * @see #fromJson(JsonReader, TypeToken) */ @SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"}) public T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException { return (T) fromJson(reader, TypeToken.get(typeOfT)); } /** * Reads the next JSON value from {@code reader} and converts it to an object of type {@code * typeOfT}. Returns {@code null}, if the {@code reader} is at EOF. This method is useful if the * specified object is a generic type. For non-generic objects, {@link #fromJson(JsonReader, * Type)} can be called, or {@link TypeToken#get(Class)} can be used to create the type token. * *

Unlike the other {@code fromJson} methods, no exception is thrown if the JSON data has * multiple top-level JSON elements, or if there is trailing data. * *

If the {@code Gson} instance has an {@linkplain GsonBuilder#setStrictness(Strictness) * explicit strictness setting}, this setting will be used for reading the JSON regardless of the * {@linkplain JsonReader#getStrictness() strictness} of the provided {@link JsonReader}. For * legacy reasons, if the {@code Gson} instance has no explicit strictness setting and the reader * does not have the strictness {@link Strictness#STRICT}, the JSON will be written in {@link * Strictness#LENIENT} mode.
* Note that in all cases the old strictness setting of the reader will be restored when this * method returns. * * @param the type of the desired object * @param reader the reader whose next JSON value should be deserialized * @param typeOfT The specific genericized type of src. You should create an anonymous subclass of * {@code TypeToken} with the specific generic type arguments. For example, to get the type * for {@code Collection}, you should use: *

   * new TypeToken<Collection<Foo>>(){}
   * 
* * @return an object of type T from the JsonReader. Returns {@code null} if {@code reader} is at * EOF. * @throws JsonIOException if there was a problem reading from the JsonReader * @throws JsonSyntaxException if json is not a valid representation for an object of the type * typeOfT * @see #fromJson(Reader, TypeToken) * @see #fromJson(JsonReader, Type) * @since 2.10 */ public T fromJson(JsonReader reader, TypeToken typeOfT) throws JsonIOException, JsonSyntaxException { boolean isEmpty = true; Strictness oldStrictness = reader.getStrictness(); if (this.strictness != null) { reader.setStrictness(this.strictness); } else if (reader.getStrictness() == Strictness.LEGACY_STRICT) { // For backward compatibility change to LENIENT if reader has default strictness LEGACY_STRICT reader.setStrictness(Strictness.LENIENT); } try { JsonToken unused = reader.peek(); isEmpty = false; TypeAdapter typeAdapter = getAdapter(typeOfT); T object = typeAdapter.read(reader); Class expectedTypeWrapped = Primitives.wrap(typeOfT.getRawType()); if (object != null && !expectedTypeWrapped.isInstance(object)) { throw new ClassCastException( "Type adapter '" + typeAdapter + "' returned wrong type; requested " + typeOfT.getRawType() + " but got instance of " + object.getClass() + "\nVerify that the adapter was registered for the correct type."); } 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); } catch (AssertionError e) { throw new AssertionError( "AssertionError (GSON " + GsonBuildConfig.VERSION + "): " + e.getMessage(), e); } finally { reader.setStrictness(oldStrictness); } } /** * 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 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, TypeToken)}. * * @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} * or if {@code json} is empty. * @throws JsonSyntaxException if json is not a valid representation for an object of type * classOfT * @since 1.3 * @see #fromJson(Reader, Class) * @see #fromJson(JsonElement, TypeToken) */ public T fromJson(JsonElement json, Class classOfT) throws JsonSyntaxException { return fromJson(json, TypeToken.get(classOfT)); } /** * 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. * *

Since {@code Type} is not parameterized by T, this method is not type-safe and should be * used carefully. If you are creating the {@code Type} from a {@link TypeToken}, prefer using * {@link #fromJson(JsonElement, TypeToken)} instead since its return type is based on the {@code * TypeToken} and is therefore more type-safe. * * @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 * @return an object of type T from the JSON. Returns {@code null} if {@code json} is {@code null} * or if {@code json} is empty. * @throws JsonSyntaxException if json is not a valid representation for an object of type typeOfT * @since 1.3 * @see #fromJson(Reader, Type) * @see #fromJson(JsonElement, Class) * @see #fromJson(JsonElement, TypeToken) */ @SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"}) public T fromJson(JsonElement json, Type typeOfT) throws JsonSyntaxException { return (T) fromJson(json, TypeToken.get(typeOfT)); } /** * 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 should create an anonymous subclass of * {@code TypeToken} with the specific generic type arguments. For example, to get the type * for {@code Collection}, you should use: *

   * new TypeToken<Collection<Foo>>(){}
   * 
* * @return an object of type T from the JSON. Returns {@code null} if {@code json} is {@code null} * or if {@code json} is empty. * @throws JsonSyntaxException if json is not a valid representation for an object of type typeOfT * @see #fromJson(Reader, TypeToken) * @see #fromJson(JsonElement, Class) * @since 2.10 */ public T fromJson(JsonElement json, TypeToken typeOfT) throws JsonSyntaxException { if (json == null) { return null; } return fromJson(new JsonTreeReader(json), typeOfT); } private static void assertFullConsumption(Object obj, JsonReader reader) { try { if (obj != null && reader.peek() != JsonToken.END_DOCUMENT) { throw new JsonSyntaxException("JSON document was not fully consumed."); } } catch (MalformedJsonException e) { throw new JsonSyntaxException(e); } catch (IOException e) { throw new JsonIOException(e); } } /** * Proxy type adapter for cyclic type graphs. * *

Important: Setting the delegate adapter is not thread-safe; instances of {@code * FutureTypeAdapter} must only be published to other threads after the delegate has been set. * * @see Gson#threadLocalAdapterResults */ static class FutureTypeAdapter extends SerializationDelegatingTypeAdapter { private TypeAdapter delegate = null; public void setDelegate(TypeAdapter typeAdapter) { if (delegate != null) { throw new AssertionError("Delegate is already set"); } delegate = typeAdapter; } private TypeAdapter delegate() { TypeAdapter delegate = this.delegate; if (delegate == null) { // Can occur when adapter is leaked to other thread or when adapter is used for // (de-)serialization // directly within the TypeAdapterFactory which requested it throw new IllegalStateException( "Adapter for type with cyclic dependency has been used" + " before dependency has been resolved"); } return delegate; } @Override public TypeAdapter getSerializationDelegate() { return delegate(); } @Override public T read(JsonReader in) throws IOException { return delegate().read(in); } @Override public void write(JsonWriter out, T value) throws IOException { delegate().write(out, value); } } @Override public String toString() { return "{serializeNulls:" + serializeNulls + ",factories:" + factories + ",instanceCreators:" + constructorConstructor + "}"; } }