2008-09-01 05:13:32 +02:00
|
|
|
/*
|
|
|
|
* 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;
|
|
|
|
|
2011-09-11 09:04:56 +02:00
|
|
|
import com.google.gson.internal.ConstructorConstructor;
|
2011-11-22 08:37:13 +01:00
|
|
|
import com.google.gson.internal.Excluder;
|
2018-05-17 18:41:21 +02:00
|
|
|
import com.google.gson.internal.GsonBuildConfig;
|
2022-01-28 20:26:28 +01:00
|
|
|
import com.google.gson.internal.LazilyParsedNumber;
|
2011-09-11 09:04:56 +02:00
|
|
|
import com.google.gson.internal.Primitives;
|
2011-08-03 04:40:18 +02:00
|
|
|
import com.google.gson.internal.Streams;
|
2011-08-03 03:19:26 +02:00
|
|
|
import com.google.gson.internal.bind.ArrayTypeAdapter;
|
2011-09-11 09:04:56 +02:00
|
|
|
import com.google.gson.internal.bind.CollectionTypeAdapterFactory;
|
2011-09-26 23:44:08 +02:00
|
|
|
import com.google.gson.internal.bind.DateTypeAdapter;
|
2014-03-26 18:59:54 +01:00
|
|
|
import com.google.gson.internal.bind.JsonAdapterAnnotationTypeAdapterFactory;
|
2011-12-03 03:37:27 +01:00
|
|
|
import com.google.gson.internal.bind.JsonTreeReader;
|
2011-12-30 09:27:24 +01:00
|
|
|
import com.google.gson.internal.bind.JsonTreeWriter;
|
2011-09-11 09:04:56 +02:00
|
|
|
import com.google.gson.internal.bind.MapTypeAdapterFactory;
|
2021-10-09 02:09:43 +02:00
|
|
|
import com.google.gson.internal.bind.NumberTypeAdapter;
|
2011-09-09 05:31:16 +02:00
|
|
|
import com.google.gson.internal.bind.ObjectTypeAdapter;
|
2011-09-11 09:04:56 +02:00
|
|
|
import com.google.gson.internal.bind.ReflectiveTypeAdapterFactory;
|
2011-08-03 03:19:26 +02:00
|
|
|
import com.google.gson.internal.bind.TypeAdapters;
|
2020-05-09 17:37:21 +02:00
|
|
|
import com.google.gson.internal.sql.SqlTypesSupport;
|
2011-08-03 02:47:36 +02:00
|
|
|
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;
|
2022-06-28 18:48:05 +02:00
|
|
|
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.text.DateFormat;
|
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.Collections;
|
|
|
|
import java.util.HashMap;
|
|
|
|
import java.util.List;
|
|
|
|
import java.util.Map;
|
2022-08-22 16:22:32 +02:00
|
|
|
import java.util.Objects;
|
2022-06-28 18:48:05 +02:00
|
|
|
import java.util.concurrent.ConcurrentHashMap;
|
2022-08-01 19:59:04 +02:00
|
|
|
import java.util.concurrent.ConcurrentMap;
|
2022-06-28 18:48:05 +02:00
|
|
|
import java.util.concurrent.atomic.AtomicLong;
|
|
|
|
import java.util.concurrent.atomic.AtomicLongArray;
|
2011-08-03 02:47:36 +02:00
|
|
|
|
2008-09-01 05:13:32 +02:00
|
|
|
/**
|
|
|
|
* 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)}
|
2015-08-10 16:04:07 +02:00
|
|
|
* methods on it. Gson instances are Thread-safe so you can reuse them freely across multiple
|
|
|
|
* threads.
|
2008-09-01 05:13:32 +02:00
|
|
|
*
|
|
|
|
* <p>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.</p>
|
|
|
|
*
|
|
|
|
* <p>Here is an example of how Gson is used for a simple Class:
|
|
|
|
*
|
|
|
|
* <pre>
|
|
|
|
* 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
|
2021-12-27 00:30:21 +01:00
|
|
|
* </pre>
|
2008-09-01 05:13:32 +02:00
|
|
|
*
|
|
|
|
* <p>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
|
2019-03-03 20:18:06 +01:00
|
|
|
* {@link #toJson(Object, Type)} or {@link #fromJson(String, Type)} method. Here is an
|
2016-02-15 23:11:23 +01:00
|
|
|
* example for serializing and deserializing a {@code ParameterizedType}:
|
2008-09-01 05:13:32 +02:00
|
|
|
*
|
|
|
|
* <pre>
|
2009-09-22 21:10:53 +02:00
|
|
|
* Type listType = new TypeToken<List<String>>() {}.getType();
|
|
|
|
* List<String> target = new LinkedList<String>();
|
2008-09-01 05:13:32 +02:00
|
|
|
* target.add("blah");
|
|
|
|
*
|
|
|
|
* Gson gson = new Gson();
|
|
|
|
* String json = gson.toJson(target, listType);
|
2009-09-22 21:10:53 +02:00
|
|
|
* List<String> target2 = gson.fromJson(json, listType);
|
2021-12-27 00:30:21 +01:00
|
|
|
* </pre>
|
2008-09-01 05:13:32 +02:00
|
|
|
*
|
|
|
|
* <p>See the <a href="https://sites.google.com/site/gson/gson-user-guide">Gson User Guide</a>
|
|
|
|
* for a more complete set of examples.</p>
|
|
|
|
*
|
2022-06-28 18:48:05 +02:00
|
|
|
* <h2>Lenient JSON handling</h2>
|
|
|
|
* For legacy reasons most of the {@code Gson} methods allow JSON data which does not
|
|
|
|
* comply with the JSON specification, regardless of whether {@link GsonBuilder#setLenient()}
|
|
|
|
* is used or not. If this behavior is not desired, the following workarounds can be used:
|
|
|
|
*
|
|
|
|
* <h3>Serialization</h3>
|
|
|
|
* <ol>
|
|
|
|
* <li>Use {@link #getAdapter(Class)} to obtain the adapter for the type to be serialized
|
|
|
|
* <li>When using an existing {@code JsonWriter}, manually apply the writer settings of this
|
|
|
|
* {@code Gson} instance listed by {@link #newJsonWriter(Writer)}.<br>
|
|
|
|
* Otherwise, when not using an existing {@code JsonWriter}, use {@link #newJsonWriter(Writer)}
|
|
|
|
* to construct one.
|
|
|
|
* <li>Call {@link TypeAdapter#write(JsonWriter, Object)}
|
|
|
|
* </ol>
|
|
|
|
*
|
|
|
|
* <h3>Deserialization</h3>
|
|
|
|
* <ol>
|
|
|
|
* <li>Use {@link #getAdapter(Class)} to obtain the adapter for the type to be deserialized
|
|
|
|
* <li>When using an existing {@code JsonReader}, manually apply the reader settings of this
|
|
|
|
* {@code Gson} instance listed by {@link #newJsonReader(Reader)}.<br>
|
|
|
|
* Otherwise, when not using an existing {@code JsonReader}, use {@link #newJsonReader(Reader)}
|
|
|
|
* to construct one.
|
|
|
|
* <li>Call {@link TypeAdapter#read(JsonReader)}
|
|
|
|
* <li>Call {@link JsonReader#peek()} and verify that the result is {@link JsonToken#END_DOCUMENT}
|
|
|
|
* to make sure there is no trailing data
|
|
|
|
* </ol>
|
|
|
|
*
|
2008-09-01 05:13:32 +02:00
|
|
|
* @see com.google.gson.reflect.TypeToken
|
|
|
|
*
|
|
|
|
* @author Inderjeet Singh
|
|
|
|
* @author Joel Leitch
|
2012-04-12 20:49:27 +02:00
|
|
|
* @author Jesse Wilson
|
2008-09-01 05:13:32 +02:00
|
|
|
*/
|
|
|
|
public final class Gson {
|
2011-11-21 06:42:30 +01:00
|
|
|
static final boolean DEFAULT_JSON_NON_EXECUTABLE = false;
|
2016-01-17 09:03:04 +01:00
|
|
|
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;
|
2021-12-31 00:08:18 +01:00
|
|
|
static final boolean DEFAULT_USE_JDK_UNSAFE = true;
|
2022-01-12 16:07:55 +01:00
|
|
|
static final String DEFAULT_DATE_PATTERN = null;
|
|
|
|
static final FieldNamingStrategy DEFAULT_FIELD_NAMING_STRATEGY = FieldNamingPolicy.IDENTITY;
|
|
|
|
static final ToNumberStrategy DEFAULT_OBJECT_TO_NUMBER_STRATEGY = ToNumberPolicy.DOUBLE;
|
|
|
|
static final ToNumberStrategy DEFAULT_NUMBER_TO_NUMBER_STRATEGY = ToNumberPolicy.LAZILY_PARSED_NUMBER;
|
2009-10-07 11:23:14 +02:00
|
|
|
|
2009-03-20 19:02:35 +01:00
|
|
|
private static final String JSON_NON_EXECUTABLE_PREFIX = ")]}'\n";
|
2009-03-17 22:15:10 +01:00
|
|
|
|
2011-11-20 16:23:08 +01:00
|
|
|
/**
|
|
|
|
* 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<Map<TypeToken<?>, FutureTypeAdapter<?>>> calls
|
2022-04-18 00:27:21 +02:00
|
|
|
= new ThreadLocal<>();
|
2011-11-20 16:23:08 +01:00
|
|
|
|
2022-08-01 19:59:04 +02:00
|
|
|
private final ConcurrentMap<TypeToken<?>, TypeAdapter<?>> typeTokenCache = new ConcurrentHashMap<>();
|
2011-11-26 16:30:38 +01:00
|
|
|
|
2011-09-11 09:04:56 +02:00
|
|
|
private final ConstructorConstructor constructorConstructor;
|
2016-06-15 01:34:34 +02:00
|
|
|
private final JsonAdapterAnnotationTypeAdapterFactory jsonAdapterFactory;
|
2009-03-17 22:15:10 +01:00
|
|
|
|
2017-09-21 03:53:10 +02:00
|
|
|
final List<TypeAdapterFactory> factories;
|
|
|
|
|
|
|
|
final Excluder excluder;
|
|
|
|
final FieldNamingStrategy fieldNamingStrategy;
|
|
|
|
final Map<Type, InstanceCreator<?>> instanceCreators;
|
|
|
|
final boolean serializeNulls;
|
|
|
|
final boolean complexMapKeySerialization;
|
|
|
|
final boolean generateNonExecutableJson;
|
|
|
|
final boolean htmlSafe;
|
|
|
|
final boolean prettyPrinting;
|
|
|
|
final boolean lenient;
|
|
|
|
final boolean serializeSpecialFloatingPointValues;
|
2021-12-31 00:08:18 +01:00
|
|
|
final boolean useJdkUnsafe;
|
2017-09-21 03:53:10 +02:00
|
|
|
final String datePattern;
|
|
|
|
final int dateStyle;
|
|
|
|
final int timeStyle;
|
|
|
|
final LongSerializationPolicy longSerializationPolicy;
|
|
|
|
final List<TypeAdapterFactory> builderFactories;
|
|
|
|
final List<TypeAdapterFactory> builderHierarchyFactories;
|
2021-10-09 02:09:43 +02:00
|
|
|
final ToNumberStrategy objectToNumberStrategy;
|
|
|
|
final ToNumberStrategy numberToNumberStrategy;
|
2022-04-17 18:05:18 +02:00
|
|
|
final List<ReflectionAccessFilter> reflectionFilters;
|
2017-09-21 03:53:10 +02:00
|
|
|
|
2008-09-01 05:13:32 +02:00
|
|
|
/**
|
|
|
|
* Constructs a Gson object with default configuration. The default configuration has the
|
|
|
|
* following settings:
|
|
|
|
* <ul>
|
|
|
|
* <li>The JSON generated by <code>toJson</code> methods is in compact representation. This
|
|
|
|
* means that all the unneeded white-space is removed. You can change this behavior with
|
|
|
|
* {@link GsonBuilder#setPrettyPrinting()}. </li>
|
|
|
|
* <li>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()}.</li>
|
|
|
|
* <li>Gson provides default serialization and deserialization for Enums, {@link Map},
|
|
|
|
* {@link java.net.URL}, {@link java.net.URI}, {@link java.util.Locale}, {@link java.util.Date},
|
|
|
|
* {@link java.math.BigDecimal}, and {@link java.math.BigInteger} classes. If you would prefer
|
|
|
|
* to change the default representation, you can do so by registering a type adapter through
|
|
|
|
* {@link GsonBuilder#registerTypeAdapter(Type, Object)}. </li>
|
2009-10-07 11:23:14 +02:00
|
|
|
* <li>The default Date format is same as {@link java.text.DateFormat#DEFAULT}. This format
|
2008-10-13 20:40:20 +02:00
|
|
|
* ignores the millisecond portion of the date during serialization. You can change
|
2008-09-01 05:13:32 +02:00
|
|
|
* this by invoking {@link GsonBuilder#setDateFormat(int)} or
|
|
|
|
* {@link GsonBuilder#setDateFormat(String)}. </li>
|
|
|
|
* <li>By default, Gson ignores the {@link com.google.gson.annotations.Expose} annotation.
|
|
|
|
* You can enable Gson to serialize/deserialize only those fields marked with this annotation
|
|
|
|
* through {@link GsonBuilder#excludeFieldsWithoutExposeAnnotation()}. </li>
|
|
|
|
* <li>By default, Gson ignores the {@link com.google.gson.annotations.Since} annotation. You
|
|
|
|
* can enable Gson to use this annotation through {@link GsonBuilder#setVersion(double)}.</li>
|
|
|
|
* <li>The default field naming policy for the output Json is same as in Java. So, a Java class
|
2014-03-26 19:07:59 +01:00
|
|
|
* field <code>versionNumber</code> will be output as <code>"versionNumber"</code> in
|
2008-09-01 05:13:32 +02:00
|
|
|
* Json. The same rules are applied for mapping incoming Json to the Java classes. You can
|
|
|
|
* change this policy through {@link GsonBuilder#setFieldNamingPolicy(FieldNamingPolicy)}.</li>
|
|
|
|
* <li>By default, Gson excludes <code>transient</code> or <code>static</code> fields from
|
|
|
|
* consideration for serialization and deserialization. You can change this behavior through
|
|
|
|
* {@link GsonBuilder#excludeFieldsWithModifiers(int...)}.</li>
|
|
|
|
* </ul>
|
|
|
|
*/
|
|
|
|
public Gson() {
|
2022-01-12 16:07:55 +01:00
|
|
|
this(Excluder.DEFAULT, DEFAULT_FIELD_NAMING_STRATEGY,
|
2016-01-17 09:03:04 +01:00
|
|
|
Collections.<Type, InstanceCreator<?>>emptyMap(), DEFAULT_SERIALIZE_NULLS,
|
|
|
|
DEFAULT_COMPLEX_MAP_KEYS, DEFAULT_JSON_NON_EXECUTABLE, DEFAULT_ESCAPE_HTML,
|
|
|
|
DEFAULT_PRETTY_PRINT, DEFAULT_LENIENT, DEFAULT_SPECIALIZE_FLOAT_VALUES,
|
2021-12-31 00:08:18 +01:00
|
|
|
DEFAULT_USE_JDK_UNSAFE,
|
2022-01-12 16:07:55 +01:00
|
|
|
LongSerializationPolicy.DEFAULT, DEFAULT_DATE_PATTERN, DateFormat.DEFAULT, DateFormat.DEFAULT,
|
2017-09-21 03:53:10 +02:00
|
|
|
Collections.<TypeAdapterFactory>emptyList(), Collections.<TypeAdapterFactory>emptyList(),
|
2022-04-17 18:05:18 +02:00
|
|
|
Collections.<TypeAdapterFactory>emptyList(), DEFAULT_OBJECT_TO_NUMBER_STRATEGY, DEFAULT_NUMBER_TO_NUMBER_STRATEGY,
|
|
|
|
Collections.<ReflectionAccessFilter>emptyList());
|
2008-09-01 05:13:32 +02:00
|
|
|
}
|
|
|
|
|
2019-03-28 17:22:36 +01:00
|
|
|
Gson(Excluder excluder, FieldNamingStrategy fieldNamingStrategy,
|
|
|
|
Map<Type, InstanceCreator<?>> instanceCreators, boolean serializeNulls,
|
2011-09-12 07:51:17 +02:00
|
|
|
boolean complexMapKeySerialization, boolean generateNonExecutableGson, boolean htmlSafe,
|
2016-01-17 09:03:04 +01:00
|
|
|
boolean prettyPrinting, boolean lenient, boolean serializeSpecialFloatingPointValues,
|
2021-12-31 00:08:18 +01:00
|
|
|
boolean useJdkUnsafe,
|
2017-09-21 03:53:10 +02:00
|
|
|
LongSerializationPolicy longSerializationPolicy, String datePattern, int dateStyle,
|
|
|
|
int timeStyle, List<TypeAdapterFactory> builderFactories,
|
|
|
|
List<TypeAdapterFactory> builderHierarchyFactories,
|
2021-10-09 02:09:43 +02:00
|
|
|
List<TypeAdapterFactory> factoriesToBeAdded,
|
2022-04-17 18:05:18 +02:00
|
|
|
ToNumberStrategy objectToNumberStrategy, ToNumberStrategy numberToNumberStrategy,
|
|
|
|
List<ReflectionAccessFilter> reflectionFilters) {
|
2016-04-25 17:26:41 +02:00
|
|
|
this.excluder = excluder;
|
|
|
|
this.fieldNamingStrategy = fieldNamingStrategy;
|
2017-09-21 03:53:10 +02:00
|
|
|
this.instanceCreators = instanceCreators;
|
2022-04-17 18:05:18 +02:00
|
|
|
this.constructorConstructor = new ConstructorConstructor(instanceCreators, useJdkUnsafe, reflectionFilters);
|
2008-09-01 05:13:32 +02:00
|
|
|
this.serializeNulls = serializeNulls;
|
2017-09-21 03:53:10 +02:00
|
|
|
this.complexMapKeySerialization = complexMapKeySerialization;
|
2009-03-17 22:15:10 +01:00
|
|
|
this.generateNonExecutableJson = generateNonExecutableGson;
|
2010-09-02 02:15:23 +02:00
|
|
|
this.htmlSafe = htmlSafe;
|
2010-11-02 00:03:41 +01:00
|
|
|
this.prettyPrinting = prettyPrinting;
|
2016-01-17 09:03:04 +01:00
|
|
|
this.lenient = lenient;
|
2017-09-21 03:53:10 +02:00
|
|
|
this.serializeSpecialFloatingPointValues = serializeSpecialFloatingPointValues;
|
2021-12-31 00:08:18 +01:00
|
|
|
this.useJdkUnsafe = useJdkUnsafe;
|
2017-09-21 03:53:10 +02:00
|
|
|
this.longSerializationPolicy = longSerializationPolicy;
|
|
|
|
this.datePattern = datePattern;
|
|
|
|
this.dateStyle = dateStyle;
|
|
|
|
this.timeStyle = timeStyle;
|
|
|
|
this.builderFactories = builderFactories;
|
|
|
|
this.builderHierarchyFactories = builderHierarchyFactories;
|
2021-10-09 02:09:43 +02:00
|
|
|
this.objectToNumberStrategy = objectToNumberStrategy;
|
|
|
|
this.numberToNumberStrategy = numberToNumberStrategy;
|
2022-04-17 18:05:18 +02:00
|
|
|
this.reflectionFilters = reflectionFilters;
|
2011-08-03 02:28:02 +02:00
|
|
|
|
2022-04-18 00:27:21 +02:00
|
|
|
List<TypeAdapterFactory> factories = new ArrayList<>();
|
2011-11-23 14:39:06 +01:00
|
|
|
|
|
|
|
// built-in type adapters that cannot be overridden
|
2012-06-30 04:37:49 +02:00
|
|
|
factories.add(TypeAdapters.JSON_ELEMENT_FACTORY);
|
2021-10-09 02:09:43 +02:00
|
|
|
factories.add(ObjectTypeAdapter.getFactory(objectToNumberStrategy));
|
2012-06-30 04:37:49 +02:00
|
|
|
|
2012-12-20 20:41:33 +01:00
|
|
|
// the excluder must precede all adapters that handle user-defined types
|
|
|
|
factories.add(excluder);
|
|
|
|
|
2017-09-21 03:53:10 +02:00
|
|
|
// users' type adapters
|
|
|
|
factories.addAll(factoriesToBeAdded);
|
2012-06-30 04:37:49 +02:00
|
|
|
|
|
|
|
// type adapters for basic platform types
|
2011-11-20 16:23:08 +01:00
|
|
|
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);
|
2015-11-05 19:45:23 +01:00
|
|
|
TypeAdapter<Number> longAdapter = longAdapter(longSerializationPolicy);
|
|
|
|
factories.add(TypeAdapters.newFactory(long.class, Long.class, longAdapter));
|
2011-11-20 16:23:08 +01:00
|
|
|
factories.add(TypeAdapters.newFactory(double.class, Double.class,
|
|
|
|
doubleAdapter(serializeSpecialFloatingPointValues)));
|
|
|
|
factories.add(TypeAdapters.newFactory(float.class, Float.class,
|
|
|
|
floatAdapter(serializeSpecialFloatingPointValues)));
|
2021-10-09 02:09:43 +02:00
|
|
|
factories.add(NumberTypeAdapter.getFactory(numberToNumberStrategy));
|
2015-11-05 23:03:51 +01:00
|
|
|
factories.add(TypeAdapters.ATOMIC_INTEGER_FACTORY);
|
|
|
|
factories.add(TypeAdapters.ATOMIC_BOOLEAN_FACTORY);
|
2015-11-05 19:45:23 +01:00
|
|
|
factories.add(TypeAdapters.newFactory(AtomicLong.class, atomicLongAdapter(longAdapter)));
|
2015-11-05 23:15:46 +01:00
|
|
|
factories.add(TypeAdapters.newFactory(AtomicLongArray.class, atomicLongArrayAdapter(longAdapter)));
|
2015-11-05 23:03:51 +01:00
|
|
|
factories.add(TypeAdapters.ATOMIC_INTEGER_ARRAY_FACTORY);
|
2011-11-20 16:23:08 +01:00
|
|
|
factories.add(TypeAdapters.CHARACTER_FACTORY);
|
|
|
|
factories.add(TypeAdapters.STRING_BUILDER_FACTORY);
|
|
|
|
factories.add(TypeAdapters.STRING_BUFFER_FACTORY);
|
2012-03-18 18:55:15 +01:00
|
|
|
factories.add(TypeAdapters.newFactory(BigDecimal.class, TypeAdapters.BIG_DECIMAL));
|
|
|
|
factories.add(TypeAdapters.newFactory(BigInteger.class, TypeAdapters.BIG_INTEGER));
|
2022-01-28 20:26:28 +01:00
|
|
|
// Add adapter for LazilyParsedNumber because user can obtain it from Gson and then try to serialize it again
|
|
|
|
factories.add(TypeAdapters.newFactory(LazilyParsedNumber.class, TypeAdapters.LAZILY_PARSED_NUMBER));
|
2011-11-20 16:23:08 +01:00
|
|
|
factories.add(TypeAdapters.URL_FACTORY);
|
|
|
|
factories.add(TypeAdapters.URI_FACTORY);
|
|
|
|
factories.add(TypeAdapters.UUID_FACTORY);
|
2015-11-07 00:41:15 +01:00
|
|
|
factories.add(TypeAdapters.CURRENCY_FACTORY);
|
2011-11-20 16:23:08 +01:00
|
|
|
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);
|
2020-05-09 17:37:21 +02:00
|
|
|
|
|
|
|
if (SqlTypesSupport.SUPPORTS_SQL_TYPES) {
|
|
|
|
factories.add(SqlTypesSupport.TIME_FACTORY);
|
|
|
|
factories.add(SqlTypesSupport.DATE_FACTORY);
|
|
|
|
factories.add(SqlTypesSupport.TIMESTAMP_FACTORY);
|
|
|
|
}
|
|
|
|
|
2011-11-20 16:23:08 +01:00
|
|
|
factories.add(ArrayTypeAdapter.FACTORY);
|
2011-12-22 23:31:43 +01:00
|
|
|
factories.add(TypeAdapters.CLASS_FACTORY);
|
2012-06-30 04:37:49 +02:00
|
|
|
|
|
|
|
// type adapters for composite and user-defined types
|
|
|
|
factories.add(new CollectionTypeAdapterFactory(constructorConstructor));
|
|
|
|
factories.add(new MapTypeAdapterFactory(constructorConstructor, complexMapKeySerialization));
|
2016-05-19 03:21:39 +02:00
|
|
|
this.jsonAdapterFactory = new JsonAdapterAnnotationTypeAdapterFactory(constructorConstructor);
|
|
|
|
factories.add(jsonAdapterFactory);
|
2014-11-04 01:59:42 +01:00
|
|
|
factories.add(TypeAdapters.ENUM_FACTORY);
|
2012-01-01 16:46:33 +01:00
|
|
|
factories.add(new ReflectiveTypeAdapterFactory(
|
2022-04-17 18:05:18 +02:00
|
|
|
constructorConstructor, fieldNamingStrategy, excluder, jsonAdapterFactory, reflectionFilters));
|
2011-11-20 16:23:08 +01:00
|
|
|
|
|
|
|
this.factories = Collections.unmodifiableList(factories);
|
2011-08-05 00:57:36 +02:00
|
|
|
}
|
|
|
|
|
2017-09-21 03:53:10 +02:00
|
|
|
/**
|
|
|
|
* Returns a new GsonBuilder containing all custom factories and configuration used by the current
|
|
|
|
* instance.
|
|
|
|
*
|
|
|
|
* @return a GsonBuilder instance.
|
|
|
|
*/
|
|
|
|
public GsonBuilder newBuilder() {
|
|
|
|
return new GsonBuilder(this);
|
|
|
|
}
|
|
|
|
|
2021-10-25 20:28:16 +02:00
|
|
|
/**
|
|
|
|
* @deprecated This method by accident exposes an internal Gson class; it might be removed in a
|
|
|
|
* future version.
|
|
|
|
*/
|
|
|
|
@Deprecated
|
2016-04-25 17:26:41 +02:00
|
|
|
public Excluder excluder() {
|
|
|
|
return excluder;
|
|
|
|
}
|
|
|
|
|
2021-10-25 20:28:16 +02:00
|
|
|
/**
|
|
|
|
* Returns the field naming strategy used by this Gson instance.
|
|
|
|
*
|
|
|
|
* @see GsonBuilder#setFieldNamingStrategy(FieldNamingStrategy)
|
|
|
|
*/
|
2016-04-25 17:26:41 +02:00
|
|
|
public FieldNamingStrategy fieldNamingStrategy() {
|
|
|
|
return fieldNamingStrategy;
|
|
|
|
}
|
|
|
|
|
2021-10-25 20:28:16 +02:00
|
|
|
/**
|
|
|
|
* Returns whether this Gson instance is serializing JSON object properties with
|
|
|
|
* {@code null} values, or just omits them.
|
|
|
|
*
|
|
|
|
* @see GsonBuilder#serializeNulls()
|
|
|
|
*/
|
2016-04-25 17:26:41 +02:00
|
|
|
public boolean serializeNulls() {
|
|
|
|
return serializeNulls;
|
|
|
|
}
|
|
|
|
|
2021-10-25 20:28:16 +02:00
|
|
|
/**
|
|
|
|
* Returns whether this Gson instance produces JSON output which is
|
|
|
|
* HTML-safe, that means all HTML characters are escaped.
|
|
|
|
*
|
|
|
|
* @see GsonBuilder#disableHtmlEscaping()
|
|
|
|
*/
|
2016-04-25 17:26:41 +02:00
|
|
|
public boolean htmlSafe() {
|
|
|
|
return htmlSafe;
|
|
|
|
}
|
|
|
|
|
2011-09-09 06:39:29 +02:00
|
|
|
private TypeAdapter<Number> doubleAdapter(boolean serializeSpecialFloatingPointValues) {
|
2011-08-05 01:12:49 +02:00
|
|
|
if (serializeSpecialFloatingPointValues) {
|
|
|
|
return TypeAdapters.DOUBLE;
|
|
|
|
}
|
2011-09-09 06:39:29 +02:00
|
|
|
return new TypeAdapter<Number>() {
|
2011-12-03 20:46:25 +01:00
|
|
|
@Override public Double read(JsonReader in) throws IOException {
|
|
|
|
if (in.peek() == JsonToken.NULL) {
|
|
|
|
in.nextNull();
|
2011-09-11 09:04:56 +02:00
|
|
|
return null;
|
|
|
|
}
|
2011-12-03 20:46:25 +01:00
|
|
|
return in.nextDouble();
|
2011-08-05 01:12:49 +02:00
|
|
|
}
|
2011-12-03 20:46:25 +01:00
|
|
|
@Override public void write(JsonWriter out, Number value) throws IOException {
|
2011-09-11 09:04:56 +02:00
|
|
|
if (value == null) {
|
2011-12-03 20:46:25 +01:00
|
|
|
out.nullValue();
|
2011-09-11 09:04:56 +02:00
|
|
|
return;
|
|
|
|
}
|
2011-09-09 06:39:29 +02:00
|
|
|
double doubleValue = value.doubleValue();
|
|
|
|
checkValidFloatingPoint(doubleValue);
|
2011-12-03 20:46:25 +01:00
|
|
|
out.value(value);
|
2011-08-05 01:12:49 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2011-09-09 06:39:29 +02:00
|
|
|
private TypeAdapter<Number> floatAdapter(boolean serializeSpecialFloatingPointValues) {
|
2011-08-05 01:12:49 +02:00
|
|
|
if (serializeSpecialFloatingPointValues) {
|
|
|
|
return TypeAdapters.FLOAT;
|
|
|
|
}
|
2011-09-09 06:39:29 +02:00
|
|
|
return new TypeAdapter<Number>() {
|
2011-12-03 20:46:25 +01:00
|
|
|
@Override public Float read(JsonReader in) throws IOException {
|
|
|
|
if (in.peek() == JsonToken.NULL) {
|
|
|
|
in.nextNull();
|
2011-09-11 09:04:56 +02:00
|
|
|
return null;
|
|
|
|
}
|
2011-12-03 20:46:25 +01:00
|
|
|
return (float) in.nextDouble();
|
2011-08-05 01:12:49 +02:00
|
|
|
}
|
2011-12-03 20:46:25 +01:00
|
|
|
@Override public void write(JsonWriter out, Number value) throws IOException {
|
2011-09-11 09:04:56 +02:00
|
|
|
if (value == null) {
|
2011-12-03 20:46:25 +01:00
|
|
|
out.nullValue();
|
2011-09-11 09:04:56 +02:00
|
|
|
return;
|
|
|
|
}
|
2011-09-09 06:39:29 +02:00
|
|
|
float floatValue = value.floatValue();
|
|
|
|
checkValidFloatingPoint(floatValue);
|
2011-12-03 20:46:25 +01:00
|
|
|
out.value(value);
|
2011-08-05 01:12:49 +02:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2015-12-27 07:39:19 +01:00
|
|
|
static void checkValidFloatingPoint(double value) {
|
2011-08-05 01:12:49 +02:00
|
|
|
if (Double.isNaN(value) || Double.isInfinite(value)) {
|
|
|
|
throw new IllegalArgumentException(value
|
|
|
|
+ " is not a valid double value as per JSON specification. To override this"
|
2013-02-04 17:05:00 +01:00
|
|
|
+ " behavior, use GsonBuilder.serializeSpecialFloatingPointValues() method.");
|
2011-08-05 01:12:49 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-11-05 19:46:54 +01:00
|
|
|
private static TypeAdapter<Number> longAdapter(LongSerializationPolicy longSerializationPolicy) {
|
2011-08-05 00:57:36 +02:00
|
|
|
if (longSerializationPolicy == LongSerializationPolicy.DEFAULT) {
|
|
|
|
return TypeAdapters.LONG;
|
|
|
|
}
|
2011-09-09 06:39:29 +02:00
|
|
|
return new TypeAdapter<Number>() {
|
2011-12-03 20:46:25 +01:00
|
|
|
@Override public Number read(JsonReader in) throws IOException {
|
|
|
|
if (in.peek() == JsonToken.NULL) {
|
|
|
|
in.nextNull();
|
2011-09-11 09:04:56 +02:00
|
|
|
return null;
|
|
|
|
}
|
2011-12-03 20:46:25 +01:00
|
|
|
return in.nextLong();
|
2011-08-05 00:57:36 +02:00
|
|
|
}
|
2011-12-03 20:46:25 +01:00
|
|
|
@Override public void write(JsonWriter out, Number value) throws IOException {
|
2011-09-11 09:04:56 +02:00
|
|
|
if (value == null) {
|
2011-12-03 20:46:25 +01:00
|
|
|
out.nullValue();
|
2011-09-11 09:04:56 +02:00
|
|
|
return;
|
|
|
|
}
|
2011-12-03 20:46:25 +01:00
|
|
|
out.value(value.toString());
|
2011-08-05 00:57:36 +02:00
|
|
|
}
|
|
|
|
};
|
2008-09-01 05:13:32 +02:00
|
|
|
}
|
2009-10-07 11:23:14 +02:00
|
|
|
|
2015-11-05 19:46:54 +01:00
|
|
|
private static TypeAdapter<AtomicLong> atomicLongAdapter(final TypeAdapter<Number> longAdapter) {
|
2015-11-05 19:45:23 +01:00
|
|
|
return new TypeAdapter<AtomicLong>() {
|
|
|
|
@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();
|
|
|
|
}
|
2015-11-05 23:15:46 +01:00
|
|
|
|
|
|
|
private static TypeAdapter<AtomicLongArray> atomicLongArrayAdapter(final TypeAdapter<Number> longAdapter) {
|
|
|
|
return new TypeAdapter<AtomicLongArray>() {
|
|
|
|
@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 {
|
2022-04-18 00:27:21 +02:00
|
|
|
List<Long> list = new ArrayList<>();
|
2015-11-05 23:15:46 +01:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2011-11-20 16:23:08 +01:00
|
|
|
/**
|
|
|
|
* Returns the type adapter for {@code} type.
|
|
|
|
*
|
|
|
|
* @throws IllegalArgumentException if this GSON cannot serialize and
|
|
|
|
* deserialize {@code type}.
|
|
|
|
*/
|
2011-12-04 11:24:07 +01:00
|
|
|
@SuppressWarnings("unchecked")
|
2011-11-20 16:23:08 +01:00
|
|
|
public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {
|
2022-08-22 16:22:32 +02:00
|
|
|
Objects.requireNonNull(type, "type must not be null");
|
2022-08-01 19:59:04 +02:00
|
|
|
TypeAdapter<?> cached = typeTokenCache.get(type);
|
2011-11-26 16:30:38 +01:00
|
|
|
if (cached != null) {
|
|
|
|
return (TypeAdapter<T>) cached;
|
|
|
|
}
|
2011-11-20 16:23:08 +01:00
|
|
|
|
|
|
|
Map<TypeToken<?>, FutureTypeAdapter<?>> threadCalls = calls.get();
|
2013-01-14 23:05:28 +01:00
|
|
|
boolean requiresThreadLocalCleanup = false;
|
2012-10-23 04:41:34 +02:00
|
|
|
if (threadCalls == null) {
|
2022-04-18 00:27:21 +02:00
|
|
|
threadCalls = new HashMap<>();
|
2012-10-23 04:41:34 +02:00
|
|
|
calls.set(threadCalls);
|
2013-01-14 23:05:28 +01:00
|
|
|
requiresThreadLocalCleanup = true;
|
2012-10-23 04:41:34 +02:00
|
|
|
}
|
|
|
|
|
2011-12-04 11:24:07 +01:00
|
|
|
// the key and value type parameters always agree
|
2011-11-20 16:23:08 +01:00
|
|
|
FutureTypeAdapter<T> ongoingCall = (FutureTypeAdapter<T>) threadCalls.get(type);
|
|
|
|
if (ongoingCall != null) {
|
|
|
|
return ongoingCall;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
2022-04-18 00:27:21 +02:00
|
|
|
FutureTypeAdapter<T> call = new FutureTypeAdapter<>();
|
2013-01-14 23:05:28 +01:00
|
|
|
threadCalls.put(type, call);
|
|
|
|
|
2011-12-23 19:27:13 +01:00
|
|
|
for (TypeAdapterFactory factory : factories) {
|
2011-11-20 16:23:08 +01:00
|
|
|
TypeAdapter<T> candidate = factory.create(this, type);
|
|
|
|
if (candidate != null) {
|
2022-08-01 19:59:04 +02:00
|
|
|
TypeAdapter<T> existingAdapter = (TypeAdapter<T>) typeTokenCache.putIfAbsent(type, candidate);
|
|
|
|
// If other thread concurrently added adapter prefer that one instead
|
|
|
|
if (existingAdapter != null) {
|
|
|
|
candidate = existingAdapter;
|
|
|
|
}
|
|
|
|
|
2011-11-20 16:23:08 +01:00
|
|
|
call.setDelegate(candidate);
|
|
|
|
return candidate;
|
|
|
|
}
|
|
|
|
}
|
2018-05-17 18:41:21 +02:00
|
|
|
throw new IllegalArgumentException("GSON (" + GsonBuildConfig.VERSION + ") cannot handle " + type);
|
2011-11-20 16:23:08 +01:00
|
|
|
} finally {
|
|
|
|
threadCalls.remove(type);
|
2013-01-14 23:05:28 +01:00
|
|
|
|
|
|
|
if (requiresThreadLocalCleanup) {
|
|
|
|
calls.remove();
|
|
|
|
}
|
2011-11-20 16:23:08 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-12-31 09:52:59 +01:00
|
|
|
/**
|
2012-04-12 20:49:27 +02:00
|
|
|
* 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:
|
|
|
|
* <p>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</code> method:
|
|
|
|
* <pre> {@code
|
|
|
|
* class StatsTypeAdapterFactory implements TypeAdapterFactory {
|
|
|
|
* public int numReads = 0;
|
|
|
|
* public int numWrites = 0;
|
2016-04-09 03:34:05 +02:00
|
|
|
* public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
|
|
|
|
* final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
|
|
|
|
* return new TypeAdapter<T>() {
|
2012-04-12 20:49:27 +02:00
|
|
|
* 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);
|
|
|
|
* }
|
|
|
|
* };
|
|
|
|
* }
|
|
|
|
* }
|
|
|
|
* } </pre>
|
|
|
|
* This factory can now be used like this:
|
|
|
|
* <pre> {@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);
|
|
|
|
* }</pre>
|
2015-09-03 15:43:34 +02:00
|
|
|
* 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
|
2015-12-27 07:39:19 +01:00
|
|
|
* that the order of registration does not prevent this method from reaching a factory they
|
2015-09-03 15:43:34 +02:00
|
|
|
* would expect to reply from this call.
|
2012-04-12 20:49:27 +02:00
|
|
|
* 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
|
2014-11-04 01:59:42 +01:00
|
|
|
* read or written.
|
2012-04-12 20:49:27 +02:00
|
|
|
* @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 <i>this</i> (the type adapter
|
2021-12-27 00:30:21 +01:00
|
|
|
* factory from where {@code getDelegateAdapter} method is being invoked).
|
2012-04-12 20:49:27 +02:00
|
|
|
* @param type Type for which the delegate adapter is being searched for.
|
|
|
|
*
|
2011-12-31 09:52:59 +01:00
|
|
|
* @since 2.2
|
|
|
|
*/
|
2012-04-12 20:49:27 +02:00
|
|
|
public <T> TypeAdapter<T> getDelegateAdapter(TypeAdapterFactory skipPast, TypeToken<T> type) {
|
2016-06-02 06:18:03 +02:00
|
|
|
// Hack. If the skipPast factory isn't registered, assume the factory is being requested via
|
|
|
|
// our @JsonAdapter annotation.
|
|
|
|
if (!factories.contains(skipPast)) {
|
|
|
|
skipPast = jsonAdapterFactory;
|
|
|
|
}
|
2011-12-31 06:30:40 +01:00
|
|
|
|
2016-06-15 01:34:34 +02:00
|
|
|
boolean skipPastFound = false;
|
2011-12-31 09:52:59 +01:00
|
|
|
for (TypeAdapterFactory factory : factories) {
|
|
|
|
if (!skipPastFound) {
|
2016-06-02 06:18:03 +02:00
|
|
|
if (factory == skipPast) {
|
|
|
|
skipPastFound = true;
|
2011-11-20 16:23:08 +01:00
|
|
|
}
|
2011-12-31 09:52:59 +01:00
|
|
|
continue;
|
|
|
|
}
|
2016-06-02 06:18:03 +02:00
|
|
|
|
2011-12-31 09:52:59 +01:00
|
|
|
TypeAdapter<T> candidate = factory.create(this, type);
|
|
|
|
if (candidate != null) {
|
|
|
|
return candidate;
|
2011-11-20 16:23:08 +01:00
|
|
|
}
|
2011-12-31 09:52:59 +01:00
|
|
|
}
|
2016-06-02 06:18:03 +02:00
|
|
|
throw new IllegalArgumentException("GSON cannot serialize " + type);
|
2011-11-20 16:23:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the type adapter for {@code} type.
|
|
|
|
*
|
|
|
|
* @throws IllegalArgumentException if this GSON cannot serialize and
|
|
|
|
* deserialize {@code type}.
|
|
|
|
*/
|
|
|
|
public <T> TypeAdapter<T> getAdapter(Class<T> type) {
|
|
|
|
return getAdapter(TypeToken.get(type));
|
|
|
|
}
|
|
|
|
|
2009-04-03 23:33:01 +02:00
|
|
|
/**
|
2009-10-07 11:23:14 +02:00
|
|
|
* This method serializes the specified object into its equivalent representation as a tree of
|
2009-10-05 20:17:52 +02:00
|
|
|
* {@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
|
2009-04-03 23:33:01 +02:00
|
|
|
* 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
|
2009-10-05 20:17:52 +02:00
|
|
|
* {@link #toJsonTree(Object, Type)} instead.
|
2009-04-03 23:33:01 +02:00
|
|
|
*
|
|
|
|
* @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) {
|
2011-05-25 18:55:57 +02:00
|
|
|
return JsonNull.INSTANCE;
|
2009-04-03 23:33:01 +02:00
|
|
|
}
|
2009-10-09 03:35:45 +02:00
|
|
|
return toJsonTree(src, src.getClass());
|
2009-04-03 23:33:01 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This method serializes the specified object, including those of generic types, into its
|
2009-10-07 11:23:14 +02:00
|
|
|
* 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.
|
2009-04-03 23:33:01 +02:00
|
|
|
*
|
|
|
|
* @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<Foo>}, you should use:
|
|
|
|
* <pre>
|
|
|
|
* Type typeOfSrc = new TypeToken<Collection<Foo>>(){}.getType();
|
|
|
|
* </pre>
|
|
|
|
* @return Json representation of {@code src}
|
|
|
|
* @since 1.4
|
|
|
|
*/
|
|
|
|
public JsonElement toJsonTree(Object src, Type typeOfSrc) {
|
2011-12-30 09:27:24 +01:00
|
|
|
JsonTreeWriter writer = new JsonTreeWriter();
|
2011-10-23 22:28:04 +02:00
|
|
|
toJson(src, typeOfSrc, writer);
|
|
|
|
return writer.get();
|
2009-04-03 23:33:01 +02:00
|
|
|
}
|
|
|
|
|
2008-09-01 05:13:32 +02:00
|
|
|
/**
|
|
|
|
* 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
|
2008-11-26 20:13:14 +01:00
|
|
|
* {@link Writer}, use {@link #toJson(Object, Appendable)} instead.
|
2008-09-01 05:13:32 +02:00
|
|
|
*
|
|
|
|
* @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) {
|
2011-05-25 18:55:57 +02:00
|
|
|
return toJson(JsonNull.INSTANCE);
|
2008-09-01 05:13:32 +02:00
|
|
|
}
|
2009-10-09 03:35:45 +02:00
|
|
|
return toJson(src, src.getClass());
|
2008-09-01 05:13:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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
|
2008-11-26 20:13:14 +01:00
|
|
|
* the object to a {@link Appendable}, use {@link #toJson(Object, Type, Appendable)} instead.
|
2008-09-01 05:13:32 +02:00
|
|
|
*
|
|
|
|
* @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<Foo>}, you should use:
|
|
|
|
* <pre>
|
|
|
|
* Type typeOfSrc = new TypeToken<Collection<Foo>>(){}.getType();
|
|
|
|
* </pre>
|
|
|
|
* @return Json representation of {@code src}
|
|
|
|
*/
|
|
|
|
public String toJson(Object src, Type typeOfSrc) {
|
|
|
|
StringWriter writer = new StringWriter();
|
2011-09-30 09:08:44 +02:00
|
|
|
toJson(src, typeOfSrc, writer);
|
2008-09-01 05:13:32 +02:00
|
|
|
return writer.toString();
|
|
|
|
}
|
2009-08-07 22:58:41 +02:00
|
|
|
|
2008-09-01 05:13:32 +02:00
|
|
|
/**
|
|
|
|
* 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
|
2008-11-26 20:13:14 +01:00
|
|
|
* {@link #toJson(Object, Type, Appendable)} instead.
|
2008-09-01 05:13:32 +02:00
|
|
|
*
|
|
|
|
* @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
|
2010-11-03 20:46:29 +01:00
|
|
|
* @throws JsonIOException if there was a problem writing to the writer
|
2008-09-01 05:13:32 +02:00
|
|
|
* @since 1.2
|
|
|
|
*/
|
2010-11-03 20:46:29 +01:00
|
|
|
public void toJson(Object src, Appendable writer) throws JsonIOException {
|
2011-01-22 23:43:43 +01:00
|
|
|
if (src != null) {
|
|
|
|
toJson(src, src.getClass(), writer);
|
|
|
|
} else {
|
2011-05-25 18:55:57 +02:00
|
|
|
toJson(JsonNull.INSTANCE, writer);
|
2008-09-01 05:13:32 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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
|
2008-11-26 20:13:14 +01:00
|
|
|
* type. For non-generic objects, use {@link #toJson(Object, Appendable)} instead.
|
2008-09-01 05:13:32 +02:00
|
|
|
*
|
|
|
|
* @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<Foo>}, you should use:
|
|
|
|
* <pre>
|
|
|
|
* Type typeOfSrc = new TypeToken<Collection<Foo>>(){}.getType();
|
|
|
|
* </pre>
|
|
|
|
* @param writer Writer to which the Json representation of src needs to be written.
|
2010-11-03 20:46:29 +01:00
|
|
|
* @throws JsonIOException if there was a problem writing to the writer
|
2008-09-01 05:13:32 +02:00
|
|
|
* @since 1.2
|
|
|
|
*/
|
2010-11-03 20:46:29 +01:00
|
|
|
public void toJson(Object src, Type typeOfSrc, Appendable writer) throws JsonIOException {
|
2011-09-30 09:08:44 +02:00
|
|
|
try {
|
|
|
|
JsonWriter jsonWriter = newJsonWriter(Streams.writerForAppendable(writer));
|
|
|
|
toJson(src, typeOfSrc, jsonWriter);
|
|
|
|
} catch (IOException e) {
|
|
|
|
throw new JsonIOException(e);
|
|
|
|
}
|
2009-08-07 22:58:41 +02:00
|
|
|
}
|
|
|
|
|
2010-09-02 02:15:23 +02:00
|
|
|
/**
|
|
|
|
* Writes the JSON representation of {@code src} of type {@code typeOfSrc} to
|
|
|
|
* {@code writer}.
|
2022-06-28 18:48:05 +02:00
|
|
|
*
|
|
|
|
* <p>The JSON data is written in {@linkplain JsonWriter#setLenient(boolean) lenient mode},
|
|
|
|
* regardless of the lenient mode setting of the provided writer. The lenient mode setting
|
|
|
|
* of the writer is restored once this method returns.
|
|
|
|
*
|
|
|
|
* <p>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.
|
|
|
|
*
|
2010-11-03 20:46:29 +01:00
|
|
|
* @throws JsonIOException if there was a problem writing to the writer
|
2010-09-02 02:15:23 +02:00
|
|
|
*/
|
2011-09-30 19:08:35 +02:00
|
|
|
@SuppressWarnings("unchecked")
|
2010-11-03 20:46:29 +01:00
|
|
|
public void toJson(Object src, Type typeOfSrc, JsonWriter writer) throws JsonIOException {
|
2011-11-20 16:23:08 +01:00
|
|
|
TypeAdapter<?> adapter = getAdapter(TypeToken.get(typeOfSrc));
|
2011-09-30 09:08:44 +02:00
|
|
|
boolean oldLenient = writer.isLenient();
|
|
|
|
writer.setLenient(true);
|
|
|
|
boolean oldHtmlSafe = writer.isHtmlSafe();
|
|
|
|
writer.setHtmlSafe(htmlSafe);
|
|
|
|
boolean oldSerializeNulls = writer.getSerializeNulls();
|
|
|
|
writer.setSerializeNulls(serializeNulls);
|
|
|
|
try {
|
|
|
|
((TypeAdapter<Object>) adapter).write(writer, src);
|
|
|
|
} catch (IOException e) {
|
|
|
|
throw new JsonIOException(e);
|
2018-05-17 18:41:21 +02:00
|
|
|
} catch (AssertionError e) {
|
2018-10-18 17:49:08 +02:00
|
|
|
AssertionError error = new AssertionError("AssertionError (GSON " + GsonBuildConfig.VERSION + "): " + e.getMessage());
|
|
|
|
error.initCause(e);
|
|
|
|
throw error;
|
2011-09-30 09:08:44 +02:00
|
|
|
} finally {
|
|
|
|
writer.setLenient(oldLenient);
|
|
|
|
writer.setHtmlSafe(oldHtmlSafe);
|
|
|
|
writer.setSerializeNulls(oldSerializeNulls);
|
|
|
|
}
|
2010-09-02 02:15:23 +02:00
|
|
|
}
|
|
|
|
|
2009-08-07 22:58:41 +02:00
|
|
|
/**
|
|
|
|
* Converts a tree of {@link JsonElement}s into its equivalent JSON representation.
|
2009-10-07 11:23:14 +02:00
|
|
|
*
|
2009-10-05 20:17:52 +02:00
|
|
|
* @param jsonElement root of a tree of {@link JsonElement}s
|
2009-08-07 22:58:41 +02:00
|
|
|
* @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();
|
|
|
|
}
|
2009-10-07 11:23:14 +02:00
|
|
|
|
2009-08-07 22:58:41 +02:00
|
|
|
/**
|
2009-10-05 20:17:52 +02:00
|
|
|
* Writes out the equivalent JSON for a tree of {@link JsonElement}s.
|
2009-10-07 11:23:14 +02:00
|
|
|
*
|
2009-10-05 20:17:52 +02:00
|
|
|
* @param jsonElement root of a tree of {@link JsonElement}s
|
2009-08-07 22:58:41 +02:00
|
|
|
* @param writer Writer to which the Json representation needs to be written
|
2010-11-03 20:46:29 +01:00
|
|
|
* @throws JsonIOException if there was a problem writing to the writer
|
2009-08-07 22:58:41 +02:00
|
|
|
* @since 1.4
|
|
|
|
*/
|
2010-11-03 20:46:29 +01:00
|
|
|
public void toJson(JsonElement jsonElement, Appendable writer) throws JsonIOException {
|
2008-11-26 20:13:14 +01:00
|
|
|
try {
|
2011-09-30 09:08:44 +02:00
|
|
|
JsonWriter jsonWriter = newJsonWriter(Streams.writerForAppendable(writer));
|
2010-11-02 00:03:41 +01:00
|
|
|
toJson(jsonElement, jsonWriter);
|
2009-08-07 22:58:41 +02:00
|
|
|
} catch (IOException e) {
|
2016-04-15 20:00:59 +02:00
|
|
|
throw new JsonIOException(e);
|
2009-10-07 11:23:14 +02:00
|
|
|
}
|
2008-09-01 05:13:32 +02:00
|
|
|
}
|
|
|
|
|
2011-09-30 09:08:44 +02:00
|
|
|
/**
|
2015-09-27 01:19:38 +02:00
|
|
|
* Returns a new JSON writer configured for the settings on this Gson instance.
|
2021-11-01 23:11:10 +01:00
|
|
|
*
|
|
|
|
* <p>The following settings are considered:
|
|
|
|
* <ul>
|
|
|
|
* <li>{@link GsonBuilder#disableHtmlEscaping()}</li>
|
|
|
|
* <li>{@link GsonBuilder#generateNonExecutableJson()}</li>
|
|
|
|
* <li>{@link GsonBuilder#serializeNulls()}</li>
|
|
|
|
* <li>{@link GsonBuilder#setLenient()}</li>
|
|
|
|
* <li>{@link GsonBuilder#setPrettyPrinting()}</li>
|
|
|
|
* </ul>
|
2011-09-30 09:08:44 +02:00
|
|
|
*/
|
2015-09-27 01:19:38 +02:00
|
|
|
public JsonWriter newJsonWriter(Writer writer) throws IOException {
|
2011-09-30 09:08:44 +02:00
|
|
|
if (generateNonExecutableJson) {
|
|
|
|
writer.write(JSON_NON_EXECUTABLE_PREFIX);
|
|
|
|
}
|
|
|
|
JsonWriter jsonWriter = new JsonWriter(writer);
|
|
|
|
if (prettyPrinting) {
|
|
|
|
jsonWriter.setIndent(" ");
|
|
|
|
}
|
2021-11-01 23:11:10 +01:00
|
|
|
jsonWriter.setHtmlSafe(htmlSafe);
|
|
|
|
jsonWriter.setLenient(lenient);
|
2011-09-30 09:08:44 +02:00
|
|
|
jsonWriter.setSerializeNulls(serializeNulls);
|
|
|
|
return jsonWriter;
|
|
|
|
}
|
|
|
|
|
2016-01-17 09:03:04 +01:00
|
|
|
/**
|
2016-05-12 14:47:03 +02:00
|
|
|
* Returns a new JSON reader configured for the settings on this Gson instance.
|
2021-11-01 23:11:10 +01:00
|
|
|
*
|
|
|
|
* <p>The following settings are considered:
|
|
|
|
* <ul>
|
|
|
|
* <li>{@link GsonBuilder#setLenient()}</li>
|
|
|
|
* </ul>
|
2016-01-17 09:03:04 +01:00
|
|
|
*/
|
|
|
|
public JsonReader newJsonReader(Reader reader) {
|
|
|
|
JsonReader jsonReader = new JsonReader(reader);
|
|
|
|
jsonReader.setLenient(lenient);
|
|
|
|
return jsonReader;
|
|
|
|
}
|
|
|
|
|
2010-09-02 02:15:23 +02:00
|
|
|
/**
|
|
|
|
* Writes the JSON for {@code jsonElement} to {@code writer}.
|
2022-06-28 18:48:05 +02:00
|
|
|
*
|
|
|
|
* <p>The JSON data is written in {@linkplain JsonWriter#setLenient(boolean) lenient mode},
|
|
|
|
* regardless of the lenient mode setting of the provided writer. The lenient mode setting
|
|
|
|
* of the writer is restored once this method returns.
|
|
|
|
*
|
|
|
|
* <p>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.
|
|
|
|
*
|
2010-11-03 20:46:29 +01:00
|
|
|
* @throws JsonIOException if there was a problem writing to the writer
|
2010-09-02 02:15:23 +02:00
|
|
|
*/
|
2010-11-03 20:46:29 +01:00
|
|
|
public void toJson(JsonElement jsonElement, JsonWriter writer) throws JsonIOException {
|
2010-09-02 02:15:23 +02:00
|
|
|
boolean oldLenient = writer.isLenient();
|
|
|
|
writer.setLenient(true);
|
|
|
|
boolean oldHtmlSafe = writer.isHtmlSafe();
|
|
|
|
writer.setHtmlSafe(htmlSafe);
|
2011-09-30 09:08:44 +02:00
|
|
|
boolean oldSerializeNulls = writer.getSerializeNulls();
|
|
|
|
writer.setSerializeNulls(serializeNulls);
|
2010-09-02 02:15:23 +02:00
|
|
|
try {
|
2011-10-01 03:10:11 +02:00
|
|
|
Streams.write(jsonElement, writer);
|
2010-09-02 02:15:23 +02:00
|
|
|
} catch (IOException e) {
|
2010-10-19 01:58:09 +02:00
|
|
|
throw new JsonIOException(e);
|
2018-05-17 18:41:21 +02:00
|
|
|
} catch (AssertionError e) {
|
2018-10-18 17:49:08 +02:00
|
|
|
AssertionError error = new AssertionError("AssertionError (GSON " + GsonBuildConfig.VERSION + "): " + e.getMessage());
|
|
|
|
error.initCause(e);
|
|
|
|
throw error;
|
2010-09-02 02:15:23 +02:00
|
|
|
} finally {
|
|
|
|
writer.setLenient(oldLenient);
|
|
|
|
writer.setHtmlSafe(oldHtmlSafe);
|
2011-09-30 09:08:44 +02:00
|
|
|
writer.setSerializeNulls(oldSerializeNulls);
|
2010-09-02 02:15:23 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-09-01 05:13:32 +02:00
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*
|
2022-06-28 18:48:05 +02:00
|
|
|
* <p>An exception is thrown if the JSON string has multiple top-level JSON elements,
|
|
|
|
* or if there is trailing data.
|
|
|
|
*
|
2008-09-01 05:13:32 +02:00
|
|
|
* @param <T> the type of the desired object
|
|
|
|
* @param json the string from which the object is to be deserialized
|
|
|
|
* @param classOfT the class of T
|
2017-09-18 09:08:22 +02:00
|
|
|
* @return an object of type T from the string. Returns {@code null} if {@code json} is {@code null}
|
|
|
|
* or if {@code json} is empty.
|
2010-11-03 20:46:29 +01:00
|
|
|
* @throws JsonSyntaxException if json is not a valid representation for an object of type
|
2008-09-01 05:13:32 +02:00
|
|
|
* classOfT
|
|
|
|
*/
|
2010-11-03 20:46:29 +01:00
|
|
|
public <T> T fromJson(String json, Class<T> classOfT) throws JsonSyntaxException {
|
2010-11-01 23:46:20 +01:00
|
|
|
Object object = fromJson(json, (Type) classOfT);
|
2011-03-30 15:59:06 +02:00
|
|
|
return Primitives.wrap(classOfT).cast(object);
|
2008-09-01 05:13:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*
|
2022-06-28 18:48:05 +02:00
|
|
|
* <p>An exception is thrown if the JSON string has multiple top-level JSON elements,
|
|
|
|
* or if there is trailing data.
|
|
|
|
*
|
2008-09-01 05:13:32 +02:00
|
|
|
* @param <T> the type of the desired object
|
|
|
|
* @param json the string from which the object is to be deserialized
|
|
|
|
* @param typeOfT The specific genericized type of src. You can obtain this type by using the
|
|
|
|
* {@link com.google.gson.reflect.TypeToken} class. For example, to get the type for
|
|
|
|
* {@code Collection<Foo>}, you should use:
|
|
|
|
* <pre>
|
|
|
|
* Type typeOfT = new TypeToken<Collection<Foo>>(){}.getType();
|
|
|
|
* </pre>
|
2019-02-17 09:32:43 +01:00
|
|
|
* @return an object of type T from the string. Returns {@code null} if {@code json} is {@code null}
|
|
|
|
* or if {@code json} is empty.
|
2008-09-01 05:13:32 +02:00
|
|
|
* @throws JsonParseException if json is not a valid representation for an object of type typeOfT
|
2010-11-03 20:46:29 +01:00
|
|
|
* @throws JsonSyntaxException if json is not a valid representation for an object of type
|
2008-09-01 05:13:32 +02:00
|
|
|
*/
|
|
|
|
@SuppressWarnings("unchecked")
|
2010-11-03 20:46:29 +01:00
|
|
|
public <T> T fromJson(String json, Type typeOfT) throws JsonSyntaxException {
|
2010-10-22 18:06:59 +02:00
|
|
|
if (json == null) {
|
|
|
|
return null;
|
|
|
|
}
|
2011-11-13 01:04:39 +01:00
|
|
|
StringReader reader = new StringReader(json);
|
|
|
|
T target = (T) fromJson(reader, typeOfT);
|
|
|
|
return target;
|
2008-09-01 05:13:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*
|
2022-06-28 18:48:05 +02:00
|
|
|
* <p>An exception is thrown if the JSON data has multiple top-level JSON elements,
|
|
|
|
* or if there is trailing data.
|
|
|
|
*
|
2008-09-01 05:13:32 +02:00
|
|
|
* @param <T> 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
|
2014-03-30 00:28:52 +01:00
|
|
|
* @return an object of type T from the string. Returns {@code null} if {@code json} is at EOF.
|
2010-11-03 20:46:29 +01:00
|
|
|
* @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
|
2008-09-01 05:13:32 +02:00
|
|
|
* @since 1.2
|
|
|
|
*/
|
2010-11-03 20:46:29 +01:00
|
|
|
public <T> T fromJson(Reader json, Class<T> classOfT) throws JsonSyntaxException, JsonIOException {
|
2016-01-17 09:03:04 +01:00
|
|
|
JsonReader jsonReader = newJsonReader(json);
|
2010-11-10 03:02:57 +01:00
|
|
|
Object object = fromJson(jsonReader, classOfT);
|
2010-11-25 00:22:13 +01:00
|
|
|
assertFullConsumption(object, jsonReader);
|
2011-03-30 15:59:06 +02:00
|
|
|
return Primitives.wrap(classOfT).cast(object);
|
2008-09-01 05:13:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*
|
2022-06-28 18:48:05 +02:00
|
|
|
* <p>An exception is thrown if the JSON data has multiple top-level JSON elements,
|
|
|
|
* or if there is trailing data.
|
|
|
|
*
|
2008-09-01 05:13:32 +02:00
|
|
|
* @param <T> the type of the desired object
|
|
|
|
* @param json the reader producing Json from which the object is to be deserialized
|
|
|
|
* @param typeOfT The specific genericized type of src. You can obtain this type by using the
|
|
|
|
* {@link com.google.gson.reflect.TypeToken} class. For example, to get the type for
|
|
|
|
* {@code Collection<Foo>}, you should use:
|
|
|
|
* <pre>
|
|
|
|
* Type typeOfT = new TypeToken<Collection<Foo>>(){}.getType();
|
|
|
|
* </pre>
|
2014-03-30 00:28:52 +01:00
|
|
|
* @return an object of type T from the json. Returns {@code null} if {@code json} is at EOF.
|
2010-11-03 20:46:29 +01:00
|
|
|
* @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
|
2008-09-01 05:13:32 +02:00
|
|
|
* @since 1.2
|
|
|
|
*/
|
2011-12-04 11:24:07 +01:00
|
|
|
@SuppressWarnings("unchecked")
|
2010-11-03 20:46:29 +01:00
|
|
|
public <T> T fromJson(Reader json, Type typeOfT) throws JsonIOException, JsonSyntaxException {
|
2016-01-17 09:03:04 +01:00
|
|
|
JsonReader jsonReader = newJsonReader(json);
|
2011-11-13 21:04:29 +01:00
|
|
|
T object = (T) fromJson(jsonReader, typeOfT);
|
2010-11-25 00:22:13 +01:00
|
|
|
assertFullConsumption(object, jsonReader);
|
|
|
|
return object;
|
|
|
|
}
|
|
|
|
|
|
|
|
private static void assertFullConsumption(Object obj, JsonReader reader) {
|
|
|
|
try {
|
|
|
|
if (obj != null && reader.peek() != JsonToken.END_DOCUMENT) {
|
2022-06-28 18:48:05 +02:00
|
|
|
throw new JsonSyntaxException("JSON document was not fully consumed.");
|
2010-11-25 00:22:13 +01:00
|
|
|
}
|
|
|
|
} catch (MalformedJsonException e) {
|
|
|
|
throw new JsonSyntaxException(e);
|
|
|
|
} catch (IOException e) {
|
|
|
|
throw new JsonIOException(e);
|
|
|
|
}
|
2010-09-02 02:15:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Reads the next JSON value from {@code reader} and convert it to an object
|
2014-03-30 00:28:52 +01:00
|
|
|
* of type {@code typeOfT}. Returns {@code null}, if the {@code reader} is at EOF.
|
2022-06-28 18:48:05 +02:00
|
|
|
* Since Type is not parameterized by T, this method is type unsafe and should be used carefully.
|
|
|
|
*
|
|
|
|
* <p>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.
|
|
|
|
*
|
|
|
|
* <p>The JSON data is parsed in {@linkplain JsonReader#setLenient(boolean) lenient mode},
|
|
|
|
* regardless of the lenient mode setting of the provided reader. The lenient mode setting
|
|
|
|
* of the reader is restored once this method returns.
|
2010-11-03 20:46:29 +01:00
|
|
|
*
|
|
|
|
* @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
|
2010-09-02 02:15:23 +02:00
|
|
|
*/
|
2010-11-03 20:46:29 +01:00
|
|
|
@SuppressWarnings("unchecked")
|
|
|
|
public <T> T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException {
|
2011-09-11 09:04:56 +02:00
|
|
|
boolean isEmpty = true;
|
2010-09-02 02:15:23 +02:00
|
|
|
boolean oldLenient = reader.isLenient();
|
|
|
|
reader.setLenient(true);
|
|
|
|
try {
|
2011-09-11 09:04:56 +02:00
|
|
|
reader.peek();
|
|
|
|
isEmpty = false;
|
2012-10-11 05:20:36 +02:00
|
|
|
TypeToken<T> typeToken = (TypeToken<T>) TypeToken.get(typeOfT);
|
2012-10-23 04:40:14 +02:00
|
|
|
TypeAdapter<T> typeAdapter = getAdapter(typeToken);
|
2012-10-11 05:20:36 +02:00
|
|
|
T object = typeAdapter.read(reader);
|
|
|
|
return object;
|
2011-09-11 09:04:56 +02:00
|
|
|
} 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);
|
2011-10-24 03:32:46 +02:00
|
|
|
} catch (IllegalStateException e) {
|
|
|
|
throw new JsonSyntaxException(e);
|
2011-08-19 05:13:06 +02:00
|
|
|
} catch (IOException e) {
|
|
|
|
// TODO(inder): Figure out whether it is indeed right to rethrow this as JsonSyntaxException
|
|
|
|
throw new JsonSyntaxException(e);
|
2018-05-17 18:41:21 +02:00
|
|
|
} catch (AssertionError e) {
|
2018-10-18 17:49:08 +02:00
|
|
|
AssertionError error = new AssertionError("AssertionError (GSON " + GsonBuildConfig.VERSION + "): " + e.getMessage());
|
|
|
|
error.initCause(e);
|
|
|
|
throw error;
|
2010-09-02 02:15:23 +02:00
|
|
|
} finally {
|
|
|
|
reader.setLenient(oldLenient);
|
|
|
|
}
|
2009-02-04 02:56:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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,
|
2009-10-07 11:23:14 +02:00
|
|
|
* invoke {@link #fromJson(JsonElement, Type)}.
|
2009-02-04 02:56:28 +01:00
|
|
|
* @param <T> the type of the desired object
|
2009-10-07 11:23:14 +02:00
|
|
|
* @param json the root of the parse tree of {@link JsonElement}s from which the object is to
|
2009-02-04 02:56:28 +01:00
|
|
|
* be deserialized
|
|
|
|
* @param classOfT The class of T
|
2019-02-17 09:32:43 +01:00
|
|
|
* @return an object of type T from the json. Returns {@code null} if {@code json} is {@code null}
|
|
|
|
* or if {@code json} is empty.
|
2010-11-03 20:46:29 +01:00
|
|
|
* @throws JsonSyntaxException if json is not a valid representation for an object of type typeOfT
|
2009-02-04 02:56:28 +01:00
|
|
|
* @since 1.3
|
|
|
|
*/
|
2010-11-03 20:46:29 +01:00
|
|
|
public <T> T fromJson(JsonElement json, Class<T> classOfT) throws JsonSyntaxException {
|
2010-11-01 23:46:20 +01:00
|
|
|
Object object = fromJson(json, (Type) classOfT);
|
2011-03-30 15:59:06 +02:00
|
|
|
return Primitives.wrap(classOfT).cast(object);
|
2009-02-04 02:56:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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
|
2009-10-07 11:23:14 +02:00
|
|
|
* non-generic objects, use {@link #fromJson(JsonElement, Class)} instead.
|
2009-02-04 02:56:28 +01:00
|
|
|
*
|
|
|
|
* @param <T> the type of the desired object
|
2009-10-07 11:23:14 +02:00
|
|
|
* @param json the root of the parse tree of {@link JsonElement}s from which the object is to
|
2009-02-04 02:56:28 +01:00
|
|
|
* be deserialized
|
|
|
|
* @param typeOfT The specific genericized type of src. You can obtain this type by using the
|
|
|
|
* {@link com.google.gson.reflect.TypeToken} class. For example, to get the type for
|
|
|
|
* {@code Collection<Foo>}, you should use:
|
|
|
|
* <pre>
|
|
|
|
* Type typeOfT = new TypeToken<Collection<Foo>>(){}.getType();
|
|
|
|
* </pre>
|
2019-02-17 09:32:43 +01:00
|
|
|
* @return an object of type T from the json. Returns {@code null} if {@code json} is {@code null}
|
|
|
|
* or if {@code json} is empty.
|
2010-11-03 20:46:29 +01:00
|
|
|
* @throws JsonSyntaxException if json is not a valid representation for an object of type typeOfT
|
2009-02-04 02:56:28 +01:00
|
|
|
* @since 1.3
|
|
|
|
*/
|
2011-12-04 11:24:07 +01:00
|
|
|
@SuppressWarnings("unchecked")
|
2010-11-03 20:46:29 +01:00
|
|
|
public <T> T fromJson(JsonElement json, Type typeOfT) throws JsonSyntaxException {
|
2009-05-14 22:18:45 +02:00
|
|
|
if (json == null) {
|
|
|
|
return null;
|
|
|
|
}
|
2011-12-03 03:37:27 +01:00
|
|
|
return (T) fromJson(new JsonTreeReader(json), typeOfT);
|
2008-09-01 05:13:32 +02:00
|
|
|
}
|
|
|
|
|
2011-11-20 16:23:08 +01:00
|
|
|
static class FutureTypeAdapter<T> extends TypeAdapter<T> {
|
|
|
|
private TypeAdapter<T> delegate;
|
|
|
|
|
|
|
|
public void setDelegate(TypeAdapter<T> typeAdapter) {
|
|
|
|
if (delegate != null) {
|
|
|
|
throw new AssertionError();
|
|
|
|
}
|
|
|
|
delegate = typeAdapter;
|
|
|
|
}
|
|
|
|
|
2011-12-03 20:46:25 +01:00
|
|
|
@Override public T read(JsonReader in) throws IOException {
|
2011-11-20 16:23:08 +01:00
|
|
|
if (delegate == null) {
|
|
|
|
throw new IllegalStateException();
|
|
|
|
}
|
2011-12-03 20:46:25 +01:00
|
|
|
return delegate.read(in);
|
2011-11-20 16:23:08 +01:00
|
|
|
}
|
|
|
|
|
2011-12-03 20:46:25 +01:00
|
|
|
@Override public void write(JsonWriter out, T value) throws IOException {
|
2011-11-20 16:23:08 +01:00
|
|
|
if (delegate == null) {
|
|
|
|
throw new IllegalStateException();
|
|
|
|
}
|
2011-12-03 20:46:25 +01:00
|
|
|
delegate.write(out, value);
|
2011-11-20 16:23:08 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-07 11:23:14 +02:00
|
|
|
@Override
|
2008-09-16 20:28:31 +02:00
|
|
|
public String toString() {
|
2014-03-09 09:36:24 +01:00
|
|
|
return new StringBuilder("{serializeNulls:")
|
|
|
|
.append(serializeNulls)
|
2016-12-20 16:00:33 +01:00
|
|
|
.append(",factories:").append(factories)
|
2011-09-11 09:04:56 +02:00
|
|
|
.append(",instanceCreators:").append(constructorConstructor)
|
2012-12-20 20:41:33 +01:00
|
|
|
.append("}")
|
|
|
|
.toString();
|
2008-09-16 20:28:31 +02:00
|
|
|
}
|
2008-09-01 05:13:32 +02:00
|
|
|
}
|