/* * 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.smartandroid.sa.json; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.io.StringWriter; import java.io.Writer; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.lang.reflect.Type; import java.util.LinkedList; import java.util.List; import java.util.Map; import com.smartandroid.sa.json.internal.Streams; import com.smartandroid.sa.json.internal.bind.ArrayTypeAdapter; import com.smartandroid.sa.json.internal.bind.CollectionTypeAdapter; import com.smartandroid.sa.json.internal.bind.MiniGson; import com.smartandroid.sa.json.internal.bind.ReflectiveTypeAdapter; import com.smartandroid.sa.json.internal.bind.StringToValueMapTypeAdapter; import com.smartandroid.sa.json.internal.bind.TypeAdapter; import com.smartandroid.sa.json.internal.bind.TypeAdapters; import com.smartandroid.sa.json.reflect.TypeToken; import com.smartandroid.sa.json.stream.JsonReader; import com.smartandroid.sa.json.stream.JsonToken; import com.smartandroid.sa.json.stream.JsonWriter; import com.smartandroid.sa.json.stream.MalformedJsonException; /** * This is the main class for using Gson. Gson is typically used by first * constructing a Gson instance and then invoking {@link #toJson(Object)} or * {@link #fromJson(String, Class)} methods on it. * * <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 * </pre> * * </p> * * <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 {@link #toJson(Object, Type)} or * {@link #fromJson(String, Type)} method. Here is an example for serializing * and deserialing a {@code ParameterizedType}: * * <pre> * Type listType = new TypeToken<List<String>>() { * }.getType(); * List<String> target = new LinkedList<String>(); * target.add("blah"); * * Gson gson = new Gson(); * String json = gson.toJson(target, listType); * List<String> target2 = gson.fromJson(json, listType); * </pre> * * </p> * * <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> * * @see com.google.gson.reflect.TypeToken * * @author Inderjeet Singh * @author Joel Leitch */ public final class Gson { // TODO(inder): get rid of all the registerXXX methods and take all such // parameters in the // constructor instead. At the minimum, mark those methods private. static final boolean DEFAULT_JSON_NON_EXECUTABLE = false; // Default instances of plug-ins static final AnonymousAndLocalClassExclusionStrategy DEFAULT_ANON_LOCAL_CLASS_EXCLUSION_STRATEGY = new AnonymousAndLocalClassExclusionStrategy(); static final SyntheticFieldExclusionStrategy DEFAULT_SYNTHETIC_FIELD_EXCLUSION_STRATEGY = new SyntheticFieldExclusionStrategy( true); static final ModifierBasedExclusionStrategy DEFAULT_MODIFIER_BASED_EXCLUSION_STRATEGY = new ModifierBasedExclusionStrategy( new int[] { Modifier.TRANSIENT, Modifier.STATIC }); static final FieldNamingStrategy2 DEFAULT_NAMING_POLICY = new SerializedNameAnnotationInterceptingNamingPolicy( new JavaFieldNamingPolicy()); private static final ExclusionStrategy DEFAULT_EXCLUSION_STRATEGY = createExclusionStrategy(); private static final String JSON_NON_EXECUTABLE_PREFIX = ")]}'\n"; private final ExclusionStrategy deserializationExclusionStrategy; private final ExclusionStrategy serializationExclusionStrategy; private final FieldNamingStrategy2 fieldNamingPolicy; private final MappedObjectConstructor objectConstructor; /** Map containing Type or Class objects as keys */ private final ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers; /** Map containing Type or Class objects as keys */ private final ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers; private final boolean serializeNulls; private final boolean htmlSafe; private final boolean generateNonExecutableJson; private final boolean prettyPrinting; private final MiniGson miniGson; /** * 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> * <li>The default Date format is same as * {@link java.text.DateFormat#DEFAULT}. This format ignores the millisecond * portion of the date during serialization. You can change this by invoking * {@link GsonBuilder#setDateFormat(int)} or * {@link GsonBuilder#setDateFormat(String)}.</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 field <code>versionNumber</code> will be output as * <code>"versionNumber@quot;</code> in Json. The same rules are * applied for mapping incoming Json to the Java classes. You can change * this policy through * {@link GsonBuilder#setFieldNamingPolicy(FieldNamingPolicy)}.</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() { this(DEFAULT_EXCLUSION_STRATEGY, DEFAULT_EXCLUSION_STRATEGY, DEFAULT_NAMING_POLICY, new MappedObjectConstructor( DefaultTypeAdapters.getDefaultInstanceCreators()), false, DefaultTypeAdapters.getAllDefaultSerializers(), DefaultTypeAdapters.getAllDefaultDeserializers(), DEFAULT_JSON_NON_EXECUTABLE, true, false, false, LongSerializationPolicy.DEFAULT); } Gson(final ExclusionStrategy deserializationExclusionStrategy, final ExclusionStrategy serializationExclusionStrategy, final FieldNamingStrategy2 fieldNamingPolicy, final MappedObjectConstructor objectConstructor, boolean serializeNulls, final ParameterizedTypeHandlerMap<JsonSerializer<?>> serializers, final ParameterizedTypeHandlerMap<JsonDeserializer<?>> deserializers, boolean generateNonExecutableGson, boolean htmlSafe, boolean prettyPrinting, boolean serializeSpecialFloatingPointValues, LongSerializationPolicy longSerializationPolicy) { this.deserializationExclusionStrategy = deserializationExclusionStrategy; this.serializationExclusionStrategy = serializationExclusionStrategy; this.fieldNamingPolicy = fieldNamingPolicy; this.objectConstructor = objectConstructor; this.serializeNulls = serializeNulls; this.serializers = serializers; this.deserializers = deserializers; this.generateNonExecutableJson = generateNonExecutableGson; this.htmlSafe = htmlSafe; this.prettyPrinting = prettyPrinting; /* * TODO: for serialization, honor: serializationExclusionStrategy * fieldNamingPolicy serializeNulls serializers */ TypeAdapter.Factory reflectiveTypeAdapterFactory = new ReflectiveTypeAdapter.FactoryImpl() { @Override public String getFieldName(Class<?> declaringClazz, Field f, Type declaredType) { return fieldNamingPolicy.translateName(new FieldAttributes( declaringClazz, f, declaredType)); } @Override public boolean serializeField(Class<?> declaringClazz, Field f, Type declaredType) { return !Gson.this.serializationExclusionStrategy .shouldSkipField(new FieldAttributes(declaringClazz, f, declaredType)); } @Override public boolean deserializeField(Class<?> declaringClazz, Field f, Type declaredType) { return !Gson.this.deserializationExclusionStrategy .shouldSkipField(new FieldAttributes(declaringClazz, f, declaredType)); } }; TypeAdapter.Factory excludedTypeFactory = new TypeAdapter.Factory() { public <T> TypeAdapter<T> create(MiniGson context, TypeToken<T> type) { Class<?> rawType = type.getRawType(); if (serializationExclusionStrategy.shouldSkipClass(rawType) || deserializationExclusionStrategy .shouldSkipClass(rawType)) { return TypeAdapters.EXCLUDED_TYPE_ADAPTER; } else { return null; } } }; MiniGson.Builder builder = new MiniGson.Builder() .withoutDefaultFactories() .factory(TypeAdapters.BOOLEAN_FACTORY) .factory(TypeAdapters.INTEGER_FACTORY) .factory( TypeAdapters .newFactory( double.class, Double.class, doubleAdapter(serializeSpecialFloatingPointValues))) .factory( TypeAdapters .newFactory( float.class, Float.class, floatAdapter(serializeSpecialFloatingPointValues))) .factory( TypeAdapters.newFactory(long.class, Long.class, longAdapter(longSerializationPolicy))) .factory(TypeAdapters.STRING_FACTORY) .factory(excludedTypeFactory) .factory( new GsonToMiniGsonTypeAdapter(serializers, deserializers, serializeNulls)) .factory(CollectionTypeAdapter.FACTORY) .factory(StringToValueMapTypeAdapter.FACTORY) .factory(ArrayTypeAdapter.FACTORY) .factory(reflectiveTypeAdapterFactory); this.miniGson = builder.build(); } private TypeAdapter<Double> doubleAdapter( boolean serializeSpecialFloatingPointValues) { if (serializeSpecialFloatingPointValues) { return TypeAdapters.DOUBLE; } return new TypeAdapter<Double>() { @Override public Double read(JsonReader reader) throws IOException { return reader.nextDouble(); } @Override public void write(JsonWriter writer, Double value) throws IOException { checkValidFloatingPoint(value); writer.value(value); } }; } private TypeAdapter<Float> floatAdapter( boolean serializeSpecialFloatingPointValues) { if (serializeSpecialFloatingPointValues) { return TypeAdapters.FLOAT; } return new TypeAdapter<Float>() { @Override public Float read(JsonReader reader) throws IOException { return (float) reader.nextDouble(); } @Override public void write(JsonWriter writer, Float value) throws IOException { checkValidFloatingPoint(value); writer.value(value); } }; } private void checkValidFloatingPoint(double value) { if (Double.isNaN(value) || Double.isInfinite(value)) { throw new IllegalArgumentException( value + " is not a valid double value as per JSON specification. To override this" + " behavior, use GsonBuilder.serializeSpecialDoubleValues() method."); } } private TypeAdapter<Long> longAdapter( LongSerializationPolicy longSerializationPolicy) { if (longSerializationPolicy == LongSerializationPolicy.DEFAULT) { return TypeAdapters.LONG; } return new TypeAdapter<Long>() { @Override public Long read(JsonReader reader) throws IOException { return reader.nextLong(); } @Override public void write(JsonWriter writer, Long value) throws IOException { writer.value(value.toString()); } }; } private static ExclusionStrategy createExclusionStrategy() { List<ExclusionStrategy> strategies = new LinkedList<ExclusionStrategy>(); strategies.add(DEFAULT_ANON_LOCAL_CLASS_EXCLUSION_STRATEGY); strategies.add(DEFAULT_SYNTHETIC_FIELD_EXCLUSION_STRATEGY); strategies.add(DEFAULT_MODIFIER_BASED_EXCLUSION_STRATEGY); return new DisjunctionExclusionStrategy(strategies); } /** * This method serializes the specified object into its equivalent * representation as a tree of {@link JsonElement}s. This method should be * used when the specified object is not a generic type. This method uses * {@link Class#getClass()} to get the type for the specified object, but * the {@code getClass()} loses the generic type information because of the * Type Erasure feature of Java. Note that this method works fine if the any * of the object fields are of generic type, just the object itself should * not be of a generic type. If the object is of generic type, use * {@link #toJsonTree(Object, Type)} instead. * * @param src * the object for which Json representation is to be created * setting for Gson * @return Json representation of {@code src}. * @since 1.4 */ public JsonElement toJsonTree(Object src) { if (src == null) { return JsonNull.INSTANCE; } return toJsonTree(src, src.getClass()); } /** * This method serializes the specified object, including those of generic * types, into its equivalent representation as a tree of * {@link JsonElement}s. This method must be used if the specified object is * a generic type. For non-generic objects, use {@link #toJsonTree(Object)} * instead. * * @param src * the object for which JSON representation is to be created * @param typeOfSrc * The specific genericized type of src. You can obtain this type * by using the {@link com.google.gson.reflect.TypeToken} class. * For example, to get the type for {@code Collection<Foo>}, you * should use: * * <pre> * Type typeOfSrc = new TypeToken<Collection<Foo>>() { * }.getType(); * </pre> * @return Json representation of {@code src} * @since 1.4 */ @SuppressWarnings("unchecked") // the caller is required to make src and typeOfSrc consistent public JsonElement toJsonTree(Object src, Type typeOfSrc) { // Serialize 'src' to JSON, then deserialize that to a JSON tree. TypeAdapter adapter = miniGson.getAdapter(TypeToken.get(typeOfSrc)); return adapter.toJsonElement(src); } /** * This method serializes the specified object into its equivalent Json * representation. This method should be used when the specified object is * not a generic type. This method uses {@link Class#getClass()} to get the * type for the specified object, but the {@code getClass()} loses the * generic type information because of the Type Erasure feature of Java. * Note that this method works fine if the any of the object fields are of * generic type, just the object itself should not be of a generic type. If * the object is of generic type, use {@link #toJson(Object, Type)} instead. * If you want to write out the object to a {@link Writer}, use * {@link #toJson(Object, Appendable)} instead. * * @param src * the object for which Json representation is to be created * setting for Gson * @return Json representation of {@code src}. */ public String toJson(Object src) { if (src == null) { return toJson(JsonNull.INSTANCE); } return toJson(src, src.getClass()); } /** * This method serializes the specified object, including those of generic * types, into its equivalent Json representation. This method must be used * if the specified object is a generic type. For non-generic objects, use * {@link #toJson(Object)} instead. If you want to write out the object to a * {@link Appendable}, use {@link #toJson(Object, Type, Appendable)} * instead. * * @param src * the object for which JSON representation is to be created * @param typeOfSrc * The specific genericized type of src. You can obtain this type * by using the {@link com.google.gson.reflect.TypeToken} class. * For example, to get the type for {@code Collection<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(); toJson(toJsonTree(src, typeOfSrc), writer); return writer.toString(); } /** * This method serializes the specified object into its equivalent Json * representation. This method should be used when the specified object is * not a generic type. This method uses {@link Class#getClass()} to get the * type for the specified object, but the {@code getClass()} loses the * generic type information because of the Type Erasure feature of Java. * Note that this method works fine if the any of the object fields are of * generic type, just the object itself should not be of a generic type. If * the object is of generic type, use * {@link #toJson(Object, Type, Appendable)} instead. * * @param src * the object for which Json representation is to be created * setting for Gson * @param writer * Writer to which the Json representation needs to be written * @throws JsonIOException * if there was a problem writing to the writer * @since 1.2 */ public void toJson(Object src, Appendable writer) throws JsonIOException { if (src != null) { toJson(src, src.getClass(), writer); } else { toJson(JsonNull.INSTANCE, writer); } } /** * This method serializes the specified object, including those of generic * types, into its equivalent Json representation. This method must be used * if the specified object is a generic type. For non-generic objects, use * {@link #toJson(Object, Appendable)} instead. * * @param src * the object for which JSON representation is to be created * @param typeOfSrc * The specific genericized type of src. You can obtain this type * by using the {@link com.google.gson.reflect.TypeToken} class. * For example, to get the type for {@code Collection<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. * @throws JsonIOException * if there was a problem writing to the writer * @since 1.2 */ public void toJson(Object src, Type typeOfSrc, Appendable writer) throws JsonIOException { JsonElement jsonElement = toJsonTree(src, typeOfSrc); toJson(jsonElement, writer); } /** * Writes the JSON representation of {@code src} of type {@code typeOfSrc} * to {@code writer}. * * @throws JsonIOException * if there was a problem writing to the writer */ public void toJson(Object src, Type typeOfSrc, JsonWriter writer) throws JsonIOException { toJson(toJsonTree(src, typeOfSrc), writer); } /** * Converts a tree of {@link JsonElement}s into its equivalent JSON * representation. * * @param jsonElement * root of a tree of {@link JsonElement}s * @return JSON String representation of the tree * @since 1.4 */ public String toJson(JsonElement jsonElement) { StringWriter writer = new StringWriter(); toJson(jsonElement, writer); return writer.toString(); } /** * Writes out the equivalent JSON for a tree of {@link JsonElement}s. * * @param jsonElement * root of a tree of {@link JsonElement}s * @param writer * Writer to which the Json representation needs to be written * @throws JsonIOException * if there was a problem writing to the writer * @since 1.4 */ public void toJson(JsonElement jsonElement, Appendable writer) throws JsonIOException { try { if (generateNonExecutableJson) { writer.append(JSON_NON_EXECUTABLE_PREFIX); } JsonWriter jsonWriter = new JsonWriter( Streams.writerForAppendable(writer)); if (prettyPrinting) { jsonWriter.setIndent(" "); } toJson(jsonElement, jsonWriter); } catch (IOException e) { throw new RuntimeException(e); } } /** * Writes the JSON for {@code jsonElement} to {@code writer}. * * @throws JsonIOException * if there was a problem writing to the writer */ public void toJson(JsonElement jsonElement, JsonWriter writer) throws JsonIOException { boolean oldLenient = writer.isLenient(); writer.setLenient(true); boolean oldHtmlSafe = writer.isHtmlSafe(); writer.setHtmlSafe(htmlSafe); try { Streams.write(jsonElement, serializeNulls, writer); } catch (IOException e) { throw new JsonIOException(e); } finally { writer.setLenient(oldLenient); writer.setHtmlSafe(oldHtmlSafe); } } /** * This method deserializes the specified Json into an object of the * specified class. It is not suitable to use if the specified class is a * generic type since it will not have the generic type information because * of the Type Erasure feature of Java. Therefore, this method should not be * used if the desired type is a generic type. Note that this method works * fine if the any of the fields of the specified object are generics, just * the object itself should not be a generic type. For the cases when the * object is of generic type, invoke {@link #fromJson(String, Type)}. If you * have the Json in a {@link Reader} instead of a String, use * {@link #fromJson(Reader, Class)} instead. * * @param <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 * @return an object of type T from the string * @throws JsonSyntaxException * if json is not a valid representation for an object of type * classOfT */ public <T> T fromJson(String json, Class<T> classOfT) throws JsonSyntaxException { Object object = fromJson(json, (Type) classOfT); return Primitives.wrap(classOfT).cast(object); } /** * This method deserializes the specified Json into an object of the * specified type. This method is useful if the specified object is a * generic type. For non-generic objects, use * {@link #fromJson(String, Class)} instead. If you have the Json in a * {@link Reader} instead of a String, use {@link #fromJson(Reader, Type)} * instead. * * @param <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> * @return an object of type T from the string * @throws JsonParseException * if json is not a valid representation for an object of type * typeOfT * @throws JsonSyntaxException * if json is not a valid representation for an object of type */ @SuppressWarnings("unchecked") public <T> T fromJson(String json, Type typeOfT) throws JsonSyntaxException { if (json == null) { return null; } StringReader reader = new StringReader(json); T target = (T) fromJson(reader, typeOfT); return target; } /** * This method deserializes the Json read from the specified reader into an * object of the specified class. It is not suitable to use if the specified * class is a generic type since it will not have the generic type * information because of the Type Erasure feature of Java. Therefore, this * method should not be used if the desired type is a generic type. Note * that this method works fine if the any of the fields of the specified * object are generics, just the object itself should not be a generic type. * For the cases when the object is of generic type, invoke * {@link #fromJson(Reader, Type)}. If you have the Json in a String form * instead of a {@link Reader}, use {@link #fromJson(String, Class)} * instead. * * @param <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 * @return an object of type T from the string * @throws JsonIOException * if there was a problem reading from the Reader * @throws JsonSyntaxException * if json is not a valid representation for an object of type * @since 1.2 */ public <T> T fromJson(Reader json, Class<T> classOfT) throws JsonSyntaxException, JsonIOException { JsonReader jsonReader = new JsonReader(json); Object object = fromJson(jsonReader, classOfT); assertFullConsumption(object, jsonReader); return Primitives.wrap(classOfT).cast(object); } /** * This method deserializes the Json read from the specified reader into an * object of the specified type. This method is useful if the specified * object is a generic type. For non-generic objects, use * {@link #fromJson(Reader, Class)} instead. If you have the Json in a * String form instead of a {@link Reader}, use * {@link #fromJson(String, Type)} instead. * * @param <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> * @return an object of type T from the json * @throws JsonIOException * if there was a problem reading from the Reader * @throws JsonSyntaxException * if json is not a valid representation for an object of type * @since 1.2 */ public <T> T fromJson(Reader json, Type typeOfT) throws JsonIOException, JsonSyntaxException { JsonReader jsonReader = new JsonReader(json); T object = this.<T> fromJson(jsonReader, typeOfT); assertFullConsumption(object, jsonReader); return object; } private static void assertFullConsumption(Object obj, JsonReader reader) { try { if (obj != null && reader.peek() != JsonToken.END_DOCUMENT) { throw new JsonIOException( "JSON document was not fully consumed."); } } catch (MalformedJsonException e) { throw new JsonSyntaxException(e); } catch (IOException e) { throw new JsonIOException(e); } } /** * Reads the next JSON value from {@code reader} and convert it to an object * of type {@code typeOfT}. Since Type is not parameterized by T, this * method is type unsafe and should be used carefully * * @throws JsonIOException * if there was a problem writing to the Reader * @throws JsonSyntaxException * if json is not a valid representation for an object of type */ @SuppressWarnings("unchecked") public <T> T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException { boolean oldLenient = reader.isLenient(); reader.setLenient(true); try { JsonElement root = Streams.parse(reader); return (T) fromJson(root, typeOfT); } finally { reader.setLenient(oldLenient); } } /** * This method deserializes the Json read from the specified parse tree into * an object of the specified type. It is not suitable to use if the * specified class is a generic type since it will not have the generic type * information because of the Type Erasure feature of Java. Therefore, this * method should not be used if the desired type is a generic type. Note * that this method works fine if the any of the fields of the specified * object are generics, just the object itself should not be a generic type. * For the cases when the object is of generic type, invoke * {@link #fromJson(JsonElement, Type)}. * * @param <T> * 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 * @throws JsonSyntaxException * if json is not a valid representation for an object of type * typeOfT * @since 1.3 */ public <T> T fromJson(JsonElement json, Class<T> classOfT) throws JsonSyntaxException { Object object = fromJson(json, (Type) classOfT); return Primitives.wrap(classOfT).cast(object); } /** * This method deserializes the Json read from the specified parse tree into * an object of the specified type. This method is useful if the specified * object is a generic type. For non-generic objects, use * {@link #fromJson(JsonElement, Class)} instead. * * @param <T> * the type of the desired object * @param json * the root of the parse tree of {@link JsonElement}s from which * the object is to be deserialized * @param typeOfT * The specific genericized type of src. You can obtain this type * by using the {@link com.google.gson.reflect.TypeToken} class. * For example, to get the type for {@code Collection<Foo>}, you * should use: * * <pre> * Type typeOfT = new TypeToken<Collection<Foo>>() { * }.getType(); * </pre> * @return an object of type T from the json * @throws JsonSyntaxException * if json is not a valid representation for an object of type * typeOfT * @since 1.3 */ @SuppressWarnings("unchecked") public <T> T fromJson(JsonElement json, Type typeOfT) throws JsonSyntaxException { if (json == null) { return null; } JsonDeserializationContext context = new JsonDeserializationContext( new ObjectNavigator(deserializationExclusionStrategy), fieldNamingPolicy, deserializers, objectConstructor); T target = (T) context.deserialize(json, typeOfT); return target; } @Override public String toString() { StringBuilder sb = new StringBuilder("{").append("serializeNulls:") .append(serializeNulls) .append(",serializers:") .append(serializers) .append(",deserializers:") .append(deserializers) // using the name instanceCreator instead of ObjectConstructor // since the users of Gson are // more familiar with the concept of Instance Creators. // Moreover, the objectConstructor is // just a utility class around instance creators, and its // toString() only displays them. .append(",instanceCreators:").append(objectConstructor) .append("}"); return sb.toString(); } }