From ab6284c6c12cb02e9b2956f55406dac1973dd651 Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Thu, 21 May 2020 20:03:05 +0200 Subject: [PATCH 01/11] Add Gson.fromJson(..., TypeToken) overloads Previously only Gson.fromJson(..., Type) existed which is however not type-safe since the generic type parameter T used for the return type is not bound. Since these methods are often used in the form gson.fromJson(..., new TypeToken<...>(){}.getType()) this commit now adds overloads which accept a TypeToken and are therefore more type-safe. Additional changes: - Fixed some grammar mistakes - Added javadoc @see tags - Consistently write "JSON" in uppercase - More precise placement of @SuppressWarnings("unchecked") --- gson/src/main/java/com/google/gson/Gson.java | 355 ++++++++++++++---- .../java/com/google/gson/MixedStreamTest.java | 2 +- 2 files changed, 277 insertions(+), 80 deletions(-) diff --git a/gson/src/main/java/com/google/gson/Gson.java b/gson/src/main/java/com/google/gson/Gson.java index 27f3ee9246..4eddcfd7d6 100644 --- a/gson/src/main/java/com/google/gson/Gson.java +++ b/gson/src/main/java/com/google/gson/Gson.java @@ -74,23 +74,27 @@ *
  * Gson gson = new Gson(); // Or use new GsonBuilder().create();
  * MyType target = new MyType();
- * String json = gson.toJson(target); // serializes target to Json
+ * String json = gson.toJson(target); // serializes target to JSON
  * MyType target2 = gson.fromJson(json, MyType.class); // deserializes json into target2
  * 

* *

If the object that your are serializing/deserializing is a {@code ParameterizedType} * (i.e. contains at least one type parameter and may be an array) then you must use the - * {@link #toJson(Object, Type)} or {@link #fromJson(String, Type)} method. Here is an - * example for serializing and deserializing a {@code ParameterizedType}: - * + * {@link #toJson(Object, Type)} or {@link #fromJson(String, Type)} method. Gson provides + * the {@link TypeToken} class which helps you with this. Here is an example showing how + * this can be done: *

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

* *

See the Gson User Guide @@ -173,9 +177,9 @@ public final class Gson { * through {@link GsonBuilder#excludeFieldsWithoutExposeAnnotation()}. *

  • By default, Gson ignores the {@link com.google.gson.annotations.Since} annotation. You * can enable Gson to use this annotation through {@link GsonBuilder#setVersion(double)}.
  • - *
  • The default field naming policy for the output Json is same as in Java. So, a Java class + *
  • The default field naming policy for the output JSON is same as in Java. So, a Java class * field versionNumber will be output as "versionNumber" in - * Json. The same rules are applied for mapping incoming Json to the Java classes. You can + * JSON. The same rules are applied for mapping incoming JSON to the Java classes. You can * change this policy through {@link GsonBuilder#setFieldNamingPolicy(FieldNamingPolicy)}.
  • *
  • By default, Gson excludes transient or static fields from * consideration for serialization and deserialization. You can change this behavior through @@ -429,11 +433,12 @@ private static TypeAdapter atomicLongArrayAdapter(final TypeAda * @throws IllegalArgumentException if this GSON cannot serialize and * deserialize {@code type}. */ - @SuppressWarnings("unchecked") public TypeAdapter getAdapter(TypeToken type) { TypeAdapter cached = typeTokenCache.get(type == null ? NULL_KEY_SURROGATE : type); if (cached != null) { - return (TypeAdapter) cached; + @SuppressWarnings("unchecked") + TypeAdapter result = (TypeAdapter) cached; + return result; } Map, FutureTypeAdapter> threadCalls = calls.get(); @@ -445,6 +450,7 @@ public TypeAdapter getAdapter(TypeToken type) { } // the key and value type parameters always agree + @SuppressWarnings("unchecked") FutureTypeAdapter ongoingCall = (FutureTypeAdapter) threadCalls.get(type); if (ongoingCall != null) { return ongoingCall; @@ -561,13 +567,15 @@ public TypeAdapter getAdapter(Class type) { * {@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, + * of Java. Note that this method works fine if any of the object fields are of generic type, * just the object itself should not be of a generic type. If the object is of generic type, use * {@link #toJsonTree(Object, Type)} instead. * - * @param src the object for which Json representation is to be created setting for Gson - * @return Json representation of {@code src}. + * @param src the object for which JSON representation is to be created + * @return JSON representation of {@code src}. * @since 1.4 + * + * @see #toJsonTree(Object, Type) */ public JsonElement toJsonTree(Object src) { if (src == null) { @@ -591,6 +599,8 @@ public JsonElement toJsonTree(Object src) { * * @return Json representation of {@code src} * @since 1.4 + * + * @see #toJsonTree(Object) */ public JsonElement toJsonTree(Object src, Type typeOfSrc) { JsonTreeWriter writer = new JsonTreeWriter(); @@ -599,17 +609,20 @@ public JsonElement toJsonTree(Object src, Type typeOfSrc) { } /** - * This method serializes the specified object into its equivalent Json representation. + * 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, + * of Java. Note that this method works fine if any of the object fields are of generic type, * just the object itself should not be of a generic type. If the object is of generic type, use * {@link #toJson(Object, Type)} instead. If you want to write out the object to a * {@link Writer}, use {@link #toJson(Object, Appendable)} instead. * - * @param src the object for which Json representation is to be created setting for Gson + * @param src the object for which JSON representation is to be created * @return Json representation of {@code src}. + * + * @see #toJson(Object, Appendable) + * @see #toJson(Object, Type) */ public String toJson(Object src) { if (src == null) { @@ -620,7 +633,7 @@ public String toJson(Object src) { /** * 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 + * 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. * @@ -631,7 +644,10 @@ public String toJson(Object src) { *
        * Type typeOfSrc = new TypeToken<Collection<Foo>>(){}.getType();
        * 
    - * @return Json representation of {@code src} + * @return JSON representation of {@code src} + * + * @see #toJson(Object, Type, Appendable) + * @see #toJson(Object) */ public String toJson(Object src, Type typeOfSrc) { StringWriter writer = new StringWriter(); @@ -640,18 +656,22 @@ public String toJson(Object src, Type typeOfSrc) { } /** - * This method serializes the specified object into its equivalent Json representation. + * This method serializes the specified object into its equivalent JSON representation and + * writes it to the writer. * This method should be used when the specified object is not a generic type. This method uses * {@link Class#getClass()} to get the type for the specified object, but the * {@code getClass()} loses the generic type information because of the Type Erasure feature - * of Java. Note that this method works fine if the any of the object fields are of generic type, + * of Java. Note that this method works fine if any of the object fields are of generic type, * just the object itself should not be of a generic type. If the object is of generic type, use * {@link #toJson(Object, Type, Appendable)} instead. * - * @param src the object for which Json representation is to be created setting for Gson - * @param writer Writer to which the Json representation needs to be written + * @param src the object for which JSON representation is to be created + * @param writer Writer to which the JSON representation needs to be written * @throws JsonIOException if there was a problem writing to the writer * @since 1.2 + * + * @see #toJson(Object) + * @see #toJson(Object, Type, Appendable) */ public void toJson(Object src, Appendable writer) throws JsonIOException { if (src != null) { @@ -663,8 +683,9 @@ public void toJson(Object src, Appendable writer) throws JsonIOException { /** * 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. + * equivalent JSON representation and writes it to the writer. + * This method must be used if the specified object is a generic type. For non-generic objects, + * use {@link #toJson(Object, Appendable)} instead. * * @param src the object for which JSON representation is to be created * @param typeOfSrc The specific genericized type of src. You can obtain @@ -673,9 +694,12 @@ public void toJson(Object src, Appendable writer) throws JsonIOException { *
        * Type typeOfSrc = new TypeToken<Collection<Foo>>(){}.getType();
        * 
    - * @param writer Writer to which the Json representation of src needs to be written. + * @param writer Writer to which the JSON representation of src needs to be written. * @throws JsonIOException if there was a problem writing to the writer * @since 1.2 + * + * @see #toJson(Object, Type) + * @see #toJson(Object, Appendable) */ public void toJson(Object src, Type typeOfSrc, Appendable writer) throws JsonIOException { try { @@ -691,9 +715,9 @@ public void toJson(Object src, Type typeOfSrc, Appendable writer) throws JsonIOE * {@code writer}. * @throws JsonIOException if there was a problem writing to the writer */ - @SuppressWarnings("unchecked") public void toJson(Object src, Type typeOfSrc, JsonWriter writer) throws JsonIOException { - TypeAdapter adapter = getAdapter(TypeToken.get(typeOfSrc)); + @SuppressWarnings("unchecked") + TypeAdapter adapter = (TypeAdapter) getAdapter(TypeToken.get(typeOfSrc)); boolean oldLenient = writer.isLenient(); writer.setLenient(true); boolean oldHtmlSafe = writer.isHtmlSafe(); @@ -701,7 +725,7 @@ public void toJson(Object src, Type typeOfSrc, JsonWriter writer) throws JsonIOE boolean oldSerializeNulls = writer.getSerializeNulls(); writer.setSerializeNulls(serializeNulls); try { - ((TypeAdapter) adapter).write(writer, src); + adapter.write(writer, src); } catch (IOException e) { throw new JsonIOException(e); } catch (AssertionError e) { @@ -732,7 +756,7 @@ public String toJson(JsonElement jsonElement) { * 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 + * @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 */ @@ -796,13 +820,13 @@ public void toJson(JsonElement jsonElement, JsonWriter writer) throws JsonIOExce } /** - * This method deserializes the specified Json into an object of the specified class. It is not + * 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 + * {@link #fromJson(String, Type)}. If you have the JSON in a {@link Reader} instead of * a String, use {@link #fromJson(Reader, Class)} instead. * * @param the type of the desired object @@ -812,6 +836,9 @@ public void toJson(JsonElement jsonElement, JsonWriter writer) throws JsonIOExce * or if {@code json} is empty. * @throws JsonSyntaxException if json is not a valid representation for an object of type * classOfT + * + * @see #fromJson(Reader, Class) + * @see #fromJson(String, Type) */ public T fromJson(String json, Class classOfT) throws JsonSyntaxException { Object object = fromJson(json, (Type) classOfT); @@ -819,51 +846,85 @@ public T fromJson(String json, Class classOfT) throws JsonSyntaxException } /** - * This method deserializes the specified Json into an object of the specified type. This method + * 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 + * {@link #fromJson(String, Class)} instead. If you have the JSON in a {@link Reader} instead of * a String, use {@link #fromJson(Reader, Type)} instead. * + *

    Since {@code Type} is not parameterized by T, this method is not type-safe and + * should be used carefully. + * + *

    If you are creating the {@code Type} from a {@link TypeToken}, prefer using + * {@link #fromJson(String, TypeToken)} instead since its return type is based on the + * {@code TypeToken} and is therefore more type-safe. + * * @param the type of the desired object * @param json the string from which the object is to be deserialized - * @param typeOfT The specific genericized type of src. You can obtain this type by using the - * {@link com.google.gson.reflect.TypeToken} class. For example, to get the type for - * {@code Collection}, you should use: - *

    -   * Type typeOfT = new TypeToken<Collection<Foo>>(){}.getType();
    -   * 
    + * @param typeOfT The specific genericized type of src * @return an object of type T from the string. Returns {@code null} if {@code json} is {@code null} * or if {@code json} is empty. - * @throws 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 + * @throws JsonSyntaxException if json is not a valid representation for an object of type typeOfT + * + * @see #fromJson(Reader, Type) + * @see #fromJson(String, Class) + * @see #fromJson(String, TypeToken) */ - @SuppressWarnings("unchecked") public T fromJson(String json, Type typeOfT) throws JsonSyntaxException { if (json == null) { return null; } StringReader reader = new StringReader(json); + @SuppressWarnings("unchecked") T target = (T) fromJson(reader, typeOfT); return target; } /** - * This method deserializes the Json read from the specified reader into an object of the + * This method deserializes the specified JSON into an object of the specified type. This method + * is useful if the specified object is a generic type. For non-generic objects, use + * {@link #fromJson(String, Class)} instead. If you have the JSON in a {@link Reader} instead of + * a String, use {@link #fromJson(Reader, TypeToken)} instead. + * + * @param the type of the desired object + * @param json the string from which the object is to be deserialized + * @param typeOfT The specific genericized type of src. You should create an anonymous subclass of + * {@code TypeToken} with the specific generic type arguments. For example, to get the type for + * {@code Collection}, you should use: + *
    +   * new TypeToken<Collection<Foo>>(){}
    +   * 
    + * @return an object of type T from the string. Returns {@code null} if {@code json} is {@code null} + * or if {@code json} is empty. + * @throws JsonSyntaxException if json is not a valid representation for an object of the erasure type + * of typeOfT + * + * @see #fromJson(Reader, TypeToken) + * @see #fromJson(String, Class) + */ + public T fromJson(String json, TypeToken typeOfT) throws JsonSyntaxException { + return fromJson(json, typeOfT.getType()); + } + + /** + * 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 + * this method works fine if any of the fields of the specified object are generics, just the * object itself should not be a generic type. For the cases when the object is of generic type, - * invoke {@link #fromJson(Reader, Type)}. If you have the Json in a String form instead of a + * invoke {@link #fromJson(Reader, Type)}. If you have the JSON in a String form instead of a * {@link Reader}, use {@link #fromJson(String, Class)} instead. * * @param the type of the desired object - * @param json the reader producing the Json from which the object is to be deserialized. + * @param json the reader producing the JSON from which the object is to be deserialized. * @param classOfT the class of T - * @return an object of type T from the string. Returns {@code null} if {@code json} is at EOF. + * @return an object of type T from the Reader. Returns {@code null} if {@code json} is at EOF. * @throws JsonIOException if there was a problem reading from the Reader - * @throws JsonSyntaxException if json is not a valid representation for an object of type + * @throws JsonSyntaxException if json is not a valid representation for an object of type typeOfT * @since 1.2 + * + * @see #fromJson(String, Class) + * @see #fromJson(Reader, Type) */ public T fromJson(Reader json, Class classOfT) throws JsonSyntaxException, JsonIOException { JsonReader jsonReader = newJsonReader(json); @@ -873,32 +934,64 @@ public T fromJson(Reader json, Class classOfT) throws JsonSyntaxException } /** - * This method deserializes the Json read from the specified reader into an object of the + * 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 + * non-generic objects, use {@link #fromJson(Reader, Class)} instead. If you have the JSON in a * String form instead of a {@link Reader}, use {@link #fromJson(String, Type)} instead. * + *

    Since {@code Type} is not parameterized by T, this method is not type-safe and + * should be used carefully. + * + *

    If you are creating the {@code Type} from a {@link TypeToken}, prefer using + * {@link #fromJson(Reader, TypeToken)} instead since its return type is based on the + * {@code TypeToken} and is therefore more type-safe. + * * @param the type of the desired object - * @param json the reader producing Json from which the object is to be deserialized - * @param typeOfT The specific genericized type of src. You can obtain this type by using the - * {@link com.google.gson.reflect.TypeToken} class. For example, to get the type for - * {@code Collection}, you should use: - *

    -   * Type typeOfT = new TypeToken<Collection<Foo>>(){}.getType();
    -   * 
    - * @return an object of type T from the json. Returns {@code null} if {@code json} is at EOF. + * @param json the reader producing JSON from which the object is to be deserialized + * @param typeOfT The specific genericized type of src + * @return an object of type T from the Reader. Returns {@code null} if {@code json} is at EOF. * @throws JsonIOException if there was a problem reading from the Reader - * @throws JsonSyntaxException if json is not a valid representation for an object of type + * @throws JsonSyntaxException if json is not a valid representation for an object of type typeOfT * @since 1.2 + * + * @see #fromJson(String, Type) + * @see #fromJson(Reader, Class) + * @see #fromJson(Reader, TypeToken) */ - @SuppressWarnings("unchecked") public T fromJson(Reader json, Type typeOfT) throws JsonIOException, JsonSyntaxException { JsonReader jsonReader = newJsonReader(json); + @SuppressWarnings("unchecked") T object = (T) fromJson(jsonReader, typeOfT); assertFullConsumption(object, jsonReader); return 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, TypeToken)} instead. + * + * @param the type of the desired object + * @param json the reader producing JSON from which the object is to be deserialized + * @param typeOfT The specific genericized type of src. You should create an anonymous subclass of + * {@code TypeToken} with the specific generic type arguments. For example, to get the type for + * {@code Collection}, you should use: + *
    +   * new TypeToken<Collection<Foo>>(){}
    +   * 
    + * @return an object of type T from the Reader. Returns {@code null} if {@code json} is at EOF. + * @throws JsonIOException if there was a problem reading from the Reader + * @throws JsonSyntaxException if json is not a valid representation for an object of the erasure type + * of typeOfT + * + * @see #fromJson(String, TypeToken) + * @see #fromJson(Reader, Class) + */ + public T fromJson(Reader json, TypeToken typeOfT) throws JsonIOException, JsonSyntaxException { + return fromJson(json, typeOfT.getType()); + } + private static void assertFullConsumption(Object obj, JsonReader reader) { try { if (obj != null && reader.peek() != JsonToken.END_DOCUMENT) { @@ -912,14 +1005,53 @@ private static void assertFullConsumption(Object obj, JsonReader reader) { } /** - * Reads the next JSON value from {@code reader} and convert it to an object + * Reads the next JSON value from {@code reader} and converts it to an object + * of type {@code classOfT}. Returns {@code null}, if the {@code reader} is at EOF. + * It is not suitable to use if the specified class is a generic type since it + * will not have the generic type information because of the Type Erasure feature of Java. + * Therefore, this method should not be used if the desired type is a generic type. Note that + * this method works fine if any of the fields of the specified object are generics, just the + * object itself should not be a generic type. For the cases when the object is of generic type, + * invoke {@link #fromJson(JsonReader, Type)}. + * + * @param the type of the desired object + * @param reader the reader whose next JSON value should be deserialized + * @param classOfT the class of T + * @return an object of type T from the JsonReader. Returns {@code null} if {@code reader} is at EOF. + * @throws JsonIOException if there was a problem reading from the JsonReader + * @throws JsonSyntaxException if json is not a valid representation for an object of type classOfT + * + * @see #fromJson(Reader, Class) + * @see #fromJson(JsonReader, Type) + */ + public T fromJson(JsonReader reader, Class classOfT) throws JsonIOException, JsonSyntaxException { + return fromJson(reader, (Type) classOfT); + } + + /** + * Reads the next JSON value from {@code reader} and converts it to an object * of type {@code typeOfT}. Returns {@code null}, if the {@code reader} is at EOF. - * Since Type is not parameterized by T, this method is type unsafe and should be used carefully + * This method is useful if the specified object is a generic type. For non-generic objects, + * use {@link #fromJson(JsonReader, Class)} instead. * - * @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 + *

    Since {@code Type} is not parameterized by T, this method is not type-safe and + * should be used carefully. + * + *

    If you are creating the {@code Type} from a {@link TypeToken}, prefer using + * {@link #fromJson(JsonReader, TypeToken)} instead since its return type is based on the + * {@code TypeToken} and is therefore more type-safe. + * + * @param the type of the desired object + * @param reader the reader whose next JSON value should be deserialized + * @param typeOfT The specific genericized type of src + * @return an object of type T from the JsonReader. Returns {@code null} if {@code reader} is at EOF. + * @throws JsonIOException if there was a problem reading from the JsonReader + * @throws JsonSyntaxException if json is not a valid representation for an object of type typeOfT + * + * @see #fromJson(Reader, Type) + * @see #fromJson(JsonReader, Class) + * @see #fromJson(JsonReader, TypeToken) */ - @SuppressWarnings("unchecked") public T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException { boolean isEmpty = true; boolean oldLenient = reader.isLenient(); @@ -927,6 +1059,7 @@ public T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, J try { reader.peek(); isEmpty = false; + @SuppressWarnings("unchecked") TypeToken typeToken = (TypeToken) TypeToken.get(typeOfT); TypeAdapter typeAdapter = getAdapter(typeToken); T object = typeAdapter.read(reader); @@ -955,21 +1088,51 @@ public T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, J } /** - * This method deserializes the Json read from the specified parse tree into an object of the + * Reads the next JSON value from {@code reader} and converts it to an object + * of type {@code typeOfT}. Returns {@code null}, if the {@code reader} is at EOF. + * This method is useful if the specified object is a generic type. For non-generic objects, + * use {@link #fromJson(JsonReader, Class)} instead. + * + * @param the type of the desired object + * @param reader the reader whose next JSON value should be deserialized + * @param typeOfT The specific genericized type of src. You should create an anonymous subclass of + * {@code TypeToken} with the specific generic type arguments. For example, to get the type for + * {@code Collection}, you should use: + *

    +   * new TypeToken<Collection<Foo>>(){}
    +   * 
    + * @return an object of type T from the JsonReader. Returns {@code null} if {@code reader} is at EOF. + * @throws JsonIOException if there was a problem reading from the JsonReader + * @throws JsonSyntaxException if json is not a valid representation for an object of the erasure type + * of typeOfT + * + * @see #fromJson(Reader, Type) + * @see #fromJson(JsonReader, Class) + */ + public T fromJson(JsonReader reader, TypeToken typeOfT) throws JsonIOException, JsonSyntaxException { + return fromJson(reader, typeOfT.getType()); + } + + /** + * 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 + * this method works fine if any of the fields of the specified object are generics, just the * object itself should not be a generic type. For the cases when the object is of generic type, * invoke {@link #fromJson(JsonElement, Type)}. + * * @param the type of the desired object * @param json the root of the parse tree of {@link JsonElement}s from which the object is to * be deserialized * @param classOfT The class of T - * @return an object of type T from the json. Returns {@code null} if {@code json} is {@code null} + * @return an object of type T from the JSON. Returns {@code null} if {@code json} is {@code null} * or if {@code json} is empty. - * @throws JsonSyntaxException if json is not a valid representation for an object of type typeOfT + * @throws JsonSyntaxException if json is not a valid representation for an object of type classOfT * @since 1.3 + * + * @see #fromJson(Reader, Class) + * @see #fromJson(JsonElement, Type) */ public T fromJson(JsonElement json, Class classOfT) throws JsonSyntaxException { Object object = fromJson(json, (Type) classOfT); @@ -977,23 +1140,29 @@ public T fromJson(JsonElement json, Class classOfT) throws JsonSyntaxExce } /** - * This method deserializes the Json read from the specified parse tree into an object of the + * This method deserializes the JSON read from the specified parse tree into an object of the * specified type. This method is useful if the specified object is a generic type. For * non-generic objects, use {@link #fromJson(JsonElement, Class)} instead. * + *

    Since {@code Type} is not parameterized by T, this method is not type-safe and + * should be used carefully. + * + *

    If you are creating the {@code Type} from a {@link TypeToken}, prefer using + * {@link #fromJson(JsonElement, TypeToken)} instead since its return type is based on the + * {@code TypeToken} and is therefore more type-safe. + * * @param the type of the desired object * @param json the root of the parse tree of {@link JsonElement}s from which the object is to * be deserialized - * @param typeOfT The specific genericized type of src. You can obtain this type by using the - * {@link com.google.gson.reflect.TypeToken} class. For example, to get the type for - * {@code Collection}, you should use: - *

    -   * Type typeOfT = new TypeToken<Collection<Foo>>(){}.getType();
    -   * 
    - * @return an object of type T from the json. Returns {@code null} if {@code json} is {@code null} + * @param typeOfT The specific genericized type of src + * @return an object of type T from the JSON. Returns {@code null} if {@code json} is {@code null} * or if {@code json} is empty. * @throws JsonSyntaxException if json is not a valid representation for an object of type typeOfT * @since 1.3 + * + * @see #fromJson(Reader, Type) + * @see #fromJson(JsonElement, Class) + * @see #fromJson(JsonElement, TypeToken) */ @SuppressWarnings("unchecked") public T fromJson(JsonElement json, Type typeOfT) throws JsonSyntaxException { @@ -1003,6 +1172,34 @@ public T fromJson(JsonElement json, Type typeOfT) throws JsonSyntaxException return (T) fromJson(new JsonTreeReader(json), typeOfT); } + /** + * This method deserializes the JSON read from the specified parse tree into an object of the + * specified type. This method is useful if the specified object is a generic type. For + * non-generic objects, use {@link #fromJson(JsonElement, Class)} instead. + * + * @param the type of the desired object + * @param json the root of the parse tree of {@link JsonElement}s from which the object is to + * be deserialized + * @param typeOfT The specific genericized type of src. You should create an anonymous subclass of + * {@code TypeToken} with the specific generic type arguments. For example, to get the type for + * {@code Collection}, you should use: + *
    +   * new TypeToken<Collection<Foo>>(){}
    +   * 
    + * @return an object of type T from the JSON. Returns {@code null} if {@code json} is {@code null} + * or if {@code json} is empty. + * @throws JsonSyntaxException if json is not a valid representation for an object of the erasure type + * of typeOfT + * @since 1.3 + * + * @see #fromJson(Reader, Type) + * @see #fromJson(JsonElement, Class) + * @see #fromJson(JsonElement, TypeToken) + */ + public T fromJson(JsonElement json, TypeToken typeOfT) throws JsonSyntaxException { + return fromJson(json, typeOfT.getType()); + } + static class FutureTypeAdapter extends TypeAdapter { private TypeAdapter delegate; diff --git a/gson/src/test/java/com/google/gson/MixedStreamTest.java b/gson/src/test/java/com/google/gson/MixedStreamTest.java index 00eb4bc8a0..fa16659f0d 100644 --- a/gson/src/test/java/com/google/gson/MixedStreamTest.java +++ b/gson/src/test/java/com/google/gson/MixedStreamTest.java @@ -174,7 +174,7 @@ public void testReadNulls() { } catch (NullPointerException expected) { } try { - gson.fromJson(new JsonReader(new StringReader("true")), null); + gson.fromJson(new JsonReader(new StringReader("true")), (Type) null); fail(); } catch (NullPointerException expected) { } From 789bb164893dff05803171c797e1e4179c00adf0 Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Wed, 10 Jun 2020 15:49:32 +0200 Subject: [PATCH 02/11] Add to Gson.fromJson javadoc that JSON is fully consumed The newly added documentation deliberately does not state which exception is thrown because Gson.assertFullConsumption could throw either a JsonIOException or a JsonSyntaxException. --- gson/src/main/java/com/google/gson/Gson.java | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/gson/src/main/java/com/google/gson/Gson.java b/gson/src/main/java/com/google/gson/Gson.java index 4eddcfd7d6..0121b0b2c3 100644 --- a/gson/src/main/java/com/google/gson/Gson.java +++ b/gson/src/main/java/com/google/gson/Gson.java @@ -829,6 +829,9 @@ public void toJson(JsonElement jsonElement, JsonWriter writer) throws JsonIOExce * {@link #fromJson(String, Type)}. If you have the JSON in a {@link Reader} instead of * a String, use {@link #fromJson(Reader, Class)} instead. * + *

    This method tries to fully consume the JSON and throws an exception in case that is not + * possible. Use {@link #fromJson(JsonReader, Class)} if this behavior is not desired. + * * @param the type of the desired object * @param json the string from which the object is to be deserialized * @param classOfT the class of T @@ -857,6 +860,9 @@ public T fromJson(String json, Class classOfT) throws JsonSyntaxException *

    If you are creating the {@code Type} from a {@link TypeToken}, prefer using * {@link #fromJson(String, TypeToken)} instead since its return type is based on the * {@code TypeToken} and is therefore more type-safe. + * + *

    This method tries to fully consume the JSON and throws an exception in case that is not + * possible. Use {@link #fromJson(JsonReader, Type)} if this behavior is not desired. * * @param the type of the desired object * @param json the string from which the object is to be deserialized @@ -885,6 +891,9 @@ public T fromJson(String json, Type typeOfT) throws JsonSyntaxException { * {@link #fromJson(String, Class)} instead. If you have the JSON in a {@link Reader} instead of * a String, use {@link #fromJson(Reader, TypeToken)} instead. * + *

    This method tries to fully consume the JSON and throws an exception in case that is not + * possible. Use {@link #fromJson(JsonReader, TypeToken)} if this behavior is not desired. + * * @param the type of the desired object * @param json the string from which the object is to be deserialized * @param typeOfT The specific genericized type of src. You should create an anonymous subclass of @@ -914,6 +923,9 @@ public T fromJson(String json, TypeToken typeOfT) throws JsonSyntaxExcept * 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. + * + *

    This method tries to fully consume the JSON and throws an exception in case that is not + * possible. Use {@link #fromJson(JsonReader, Class)} if this behavior is not desired. * * @param the type of the desired object * @param json the reader producing the JSON from which the object is to be deserialized. @@ -945,6 +957,9 @@ public T fromJson(Reader json, Class classOfT) throws JsonSyntaxException *

    If you are creating the {@code Type} from a {@link TypeToken}, prefer using * {@link #fromJson(Reader, TypeToken)} instead since its return type is based on the * {@code TypeToken} and is therefore more type-safe. + * + *

    This method tries to fully consume the JSON and throws an exception in case that is not + * possible. Use {@link #fromJson(JsonReader, Type)} if this behavior is not desired. * * @param the type of the desired object * @param json the reader producing JSON from which the object is to be deserialized @@ -971,6 +986,9 @@ public T fromJson(Reader json, Type typeOfT) throws JsonIOException, JsonSyn * specified type. This method is useful if the specified object is a generic type. For * non-generic objects, use {@link #fromJson(Reader, Class)} instead. If you have the JSON in a * String form instead of a {@link Reader}, use {@link #fromJson(String, TypeToken)} instead. + * + *

    This method tries to fully consume the JSON and throws an exception in case that is not + * possible. Use {@link #fromJson(JsonReader, TypeToken)} if this behavior is not desired. * * @param the type of the desired object * @param json the reader producing JSON from which the object is to be deserialized From 3b64053b11f36d1a614e5e6ba5f44840cec6526a Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Wed, 2 Sep 2020 18:10:51 +0200 Subject: [PATCH 03/11] Remove unnecessary wrapping and unwrapping as TypeToken in Gson.fromJson Since the actual implementation of Gson.fromJson is TypeToken based, the TypeToken variant overloads are now the "main" implementation and the other overloads delegate to them. Previously the Type variant overloads were the "main" implementation which caused `TypeToken.getType()` followed by `TypeToken.get(...)` when the TypeToken variant overloads were used. --- gson/src/main/java/com/google/gson/Gson.java | 99 ++++++++++---------- 1 file changed, 48 insertions(+), 51 deletions(-) diff --git a/gson/src/main/java/com/google/gson/Gson.java b/gson/src/main/java/com/google/gson/Gson.java index 0121b0b2c3..19a6dcd0c0 100644 --- a/gson/src/main/java/com/google/gson/Gson.java +++ b/gson/src/main/java/com/google/gson/Gson.java @@ -875,14 +875,9 @@ public T fromJson(String json, Class classOfT) throws JsonSyntaxException * @see #fromJson(String, Class) * @see #fromJson(String, TypeToken) */ + @SuppressWarnings("unchecked") public T fromJson(String json, Type typeOfT) throws JsonSyntaxException { - if (json == null) { - return null; - } - StringReader reader = new StringReader(json); - @SuppressWarnings("unchecked") - T target = (T) fromJson(reader, typeOfT); - return target; + return (T) fromJson(json, TypeToken.get(typeOfT)); } /** @@ -911,7 +906,12 @@ public T fromJson(String json, Type typeOfT) throws JsonSyntaxException { * @see #fromJson(String, Class) */ public T fromJson(String json, TypeToken typeOfT) throws JsonSyntaxException { - return fromJson(json, typeOfT.getType()); + if (json == null) { + return null; + } + StringReader reader = new StringReader(json); + T target = fromJson(reader, typeOfT); + return target; } /** @@ -939,9 +939,7 @@ public T fromJson(String json, TypeToken typeOfT) throws JsonSyntaxExcept * @see #fromJson(Reader, Type) */ public T fromJson(Reader json, Class classOfT) throws JsonSyntaxException, JsonIOException { - JsonReader jsonReader = newJsonReader(json); - Object object = fromJson(jsonReader, classOfT); - assertFullConsumption(object, jsonReader); + Object object = fromJson(json, (Type) classOfT); return Primitives.wrap(classOfT).cast(object); } @@ -973,12 +971,9 @@ public T fromJson(Reader json, Class classOfT) throws JsonSyntaxException * @see #fromJson(Reader, Class) * @see #fromJson(Reader, TypeToken) */ + @SuppressWarnings("unchecked") public T fromJson(Reader json, Type typeOfT) throws JsonIOException, JsonSyntaxException { - JsonReader jsonReader = newJsonReader(json); - @SuppressWarnings("unchecked") - T object = (T) fromJson(jsonReader, typeOfT); - assertFullConsumption(object, jsonReader); - return object; + return (T) fromJson(json, TypeToken.get(typeOfT)); } /** @@ -1007,7 +1002,10 @@ public T fromJson(Reader json, Type typeOfT) throws JsonIOException, JsonSyn * @see #fromJson(Reader, Class) */ public T fromJson(Reader json, TypeToken typeOfT) throws JsonIOException, JsonSyntaxException { - return fromJson(json, typeOfT.getType()); + JsonReader jsonReader = newJsonReader(json); + T object = fromJson(jsonReader, typeOfT); + assertFullConsumption(object, jsonReader); + return object; } private static void assertFullConsumption(Object obj, JsonReader reader) { @@ -1070,16 +1068,41 @@ public T fromJson(JsonReader reader, Class classOfT) throws JsonIOExcepti * @see #fromJson(JsonReader, Class) * @see #fromJson(JsonReader, TypeToken) */ + @SuppressWarnings("unchecked") public T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException { + return (T) fromJson(reader, TypeToken.get(typeOfT)); + } + + /** + * Reads the next JSON value from {@code reader} and converts it to an object + * of type {@code typeOfT}. Returns {@code null}, if the {@code reader} is at EOF. + * This method is useful if the specified object is a generic type. For non-generic objects, + * use {@link #fromJson(JsonReader, Class)} instead. + * + * @param the type of the desired object + * @param reader the reader whose next JSON value should be deserialized + * @param typeOfT The specific genericized type of src. You should create an anonymous subclass of + * {@code TypeToken} with the specific generic type arguments. For example, to get the type for + * {@code Collection}, you should use: + *

    +   * new TypeToken<Collection<Foo>>(){}
    +   * 
    + * @return an object of type T from the JsonReader. Returns {@code null} if {@code reader} is at EOF. + * @throws JsonIOException if there was a problem reading from the JsonReader + * @throws JsonSyntaxException if json is not a valid representation for an object of the erasure type + * of typeOfT + * + * @see #fromJson(Reader, Type) + * @see #fromJson(JsonReader, Class) + */ + public T fromJson(JsonReader reader, TypeToken typeOfT) throws JsonIOException, JsonSyntaxException { boolean isEmpty = true; boolean oldLenient = reader.isLenient(); reader.setLenient(true); try { reader.peek(); isEmpty = false; - @SuppressWarnings("unchecked") - TypeToken typeToken = (TypeToken) TypeToken.get(typeOfT); - TypeAdapter typeAdapter = getAdapter(typeToken); + TypeAdapter typeAdapter = getAdapter(typeOfT); T object = typeAdapter.read(reader); return object; } catch (EOFException e) { @@ -1105,32 +1128,6 @@ public T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, J } } - /** - * Reads the next JSON value from {@code reader} and converts it to an object - * of type {@code typeOfT}. Returns {@code null}, if the {@code reader} is at EOF. - * This method is useful if the specified object is a generic type. For non-generic objects, - * use {@link #fromJson(JsonReader, Class)} instead. - * - * @param the type of the desired object - * @param reader the reader whose next JSON value should be deserialized - * @param typeOfT The specific genericized type of src. You should create an anonymous subclass of - * {@code TypeToken} with the specific generic type arguments. For example, to get the type for - * {@code Collection}, you should use: - *
    -   * new TypeToken<Collection<Foo>>(){}
    -   * 
    - * @return an object of type T from the JsonReader. Returns {@code null} if {@code reader} is at EOF. - * @throws JsonIOException if there was a problem reading from the JsonReader - * @throws JsonSyntaxException if json is not a valid representation for an object of the erasure type - * of typeOfT - * - * @see #fromJson(Reader, Type) - * @see #fromJson(JsonReader, Class) - */ - public T fromJson(JsonReader reader, TypeToken typeOfT) throws JsonIOException, JsonSyntaxException { - return fromJson(reader, typeOfT.getType()); - } - /** * 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 @@ -1184,10 +1181,7 @@ public T fromJson(JsonElement json, Class classOfT) throws JsonSyntaxExce */ @SuppressWarnings("unchecked") public T fromJson(JsonElement json, Type typeOfT) throws JsonSyntaxException { - if (json == null) { - return null; - } - return (T) fromJson(new JsonTreeReader(json), typeOfT); + return (T) fromJson(json, TypeToken.get(typeOfT)); } /** @@ -1215,7 +1209,10 @@ public T fromJson(JsonElement json, Type typeOfT) throws JsonSyntaxException * @see #fromJson(JsonElement, TypeToken) */ public T fromJson(JsonElement json, TypeToken typeOfT) throws JsonSyntaxException { - return fromJson(json, typeOfT.getType()); + if (json == null) { + return null; + } + return fromJson(new JsonTreeReader(json), typeOfT); } static class FutureTypeAdapter extends TypeAdapter { From 04fbb6db246bafef2fe9d1d0b7f38d02bbd3969e Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Wed, 2 Sep 2020 18:11:50 +0200 Subject: [PATCH 04/11] Trim source code whitespaces --- gson/src/main/java/com/google/gson/Gson.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/gson/src/main/java/com/google/gson/Gson.java b/gson/src/main/java/com/google/gson/Gson.java index 19a6dcd0c0..60237e9dcc 100644 --- a/gson/src/main/java/com/google/gson/Gson.java +++ b/gson/src/main/java/com/google/gson/Gson.java @@ -860,7 +860,7 @@ public T fromJson(String json, Class classOfT) throws JsonSyntaxException *

    If you are creating the {@code Type} from a {@link TypeToken}, prefer using * {@link #fromJson(String, TypeToken)} instead since its return type is based on the * {@code TypeToken} and is therefore more type-safe. - * + * *

    This method tries to fully consume the JSON and throws an exception in case that is not * possible. Use {@link #fromJson(JsonReader, Type)} if this behavior is not desired. * @@ -923,7 +923,7 @@ public T fromJson(String json, TypeToken typeOfT) throws JsonSyntaxExcept * 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. - * + * *

    This method tries to fully consume the JSON and throws an exception in case that is not * possible. Use {@link #fromJson(JsonReader, Class)} if this behavior is not desired. * @@ -955,7 +955,7 @@ public T fromJson(Reader json, Class classOfT) throws JsonSyntaxException *

    If you are creating the {@code Type} from a {@link TypeToken}, prefer using * {@link #fromJson(Reader, TypeToken)} instead since its return type is based on the * {@code TypeToken} and is therefore more type-safe. - * + * *

    This method tries to fully consume the JSON and throws an exception in case that is not * possible. Use {@link #fromJson(JsonReader, Type)} if this behavior is not desired. * @@ -981,7 +981,7 @@ public T fromJson(Reader json, Type typeOfT) throws JsonIOException, JsonSyn * specified type. This method is useful if the specified object is a generic type. For * non-generic objects, use {@link #fromJson(Reader, Class)} instead. If you have the JSON in a * String form instead of a {@link Reader}, use {@link #fromJson(String, TypeToken)} instead. - * + * *

    This method tries to fully consume the JSON and throws an exception in case that is not * possible. Use {@link #fromJson(JsonReader, TypeToken)} if this behavior is not desired. * From 224db116e31e2ca95023c3ed94835b7b13de9df7 Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Wed, 2 Sep 2020 18:14:19 +0200 Subject: [PATCH 05/11] Fix Gson.fromJson(JsonReader, Class) not casting read Object To be consistent with the other Gson.fromJson(..., Class) overloads the method should cast the result. --- gson/src/main/java/com/google/gson/Gson.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gson/src/main/java/com/google/gson/Gson.java b/gson/src/main/java/com/google/gson/Gson.java index 60237e9dcc..6542e1bdea 100644 --- a/gson/src/main/java/com/google/gson/Gson.java +++ b/gson/src/main/java/com/google/gson/Gson.java @@ -1041,7 +1041,8 @@ private static void assertFullConsumption(Object obj, JsonReader reader) { * @see #fromJson(JsonReader, Type) */ public T fromJson(JsonReader reader, Class classOfT) throws JsonIOException, JsonSyntaxException { - return fromJson(reader, (Type) classOfT); + Object object = fromJson(reader, (Type) classOfT); + return Primitives.wrap(classOfT).cast(object); } /** From b38ef2cf9fdc3177939c84e7db000e54fdd05398 Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Fri, 16 Sep 2022 20:06:10 +0200 Subject: [PATCH 06/11] Replace User Guide link in Gson documentation --- gson/src/main/java/com/google/gson/Gson.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gson/src/main/java/com/google/gson/Gson.java b/gson/src/main/java/com/google/gson/Gson.java index 8cd2a3b1ea..fac0bb31c0 100644 --- a/gson/src/main/java/com/google/gson/Gson.java +++ b/gson/src/main/java/com/google/gson/Gson.java @@ -99,7 +99,7 @@ * List<MyType> target2 = gson.fromJson(json, listType); * * - *

    See the Gson User Guide + *

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

    * *

    Lenient JSON handling

    From 17b40f8effab21fb3b70fe74f272df8f2480d6c3 Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Fri, 16 Sep 2022 20:21:46 +0200 Subject: [PATCH 07/11] Remove more references to fromJson(..., Type) --- gson/src/main/java/com/google/gson/Gson.java | 61 +++++++++----------- 1 file changed, 26 insertions(+), 35 deletions(-) diff --git a/gson/src/main/java/com/google/gson/Gson.java b/gson/src/main/java/com/google/gson/Gson.java index fac0bb31c0..83cb6aa9ea 100644 --- a/gson/src/main/java/com/google/gson/Gson.java +++ b/gson/src/main/java/com/google/gson/Gson.java @@ -941,7 +941,7 @@ public void toJson(JsonElement jsonElement, JsonWriter writer) throws JsonIOExce * 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 + * {@link #fromJson(String, TypeToken)}. If you have the JSON in a {@link Reader} instead of * a String, use {@link #fromJson(Reader, Class)} instead. * *

    An exception is thrown if the JSON string has multiple top-level JSON elements, or if there @@ -956,10 +956,10 @@ public void toJson(JsonElement jsonElement, JsonWriter writer) throws JsonIOExce * classOfT * * @see #fromJson(Reader, Class) - * @see #fromJson(String, Type) + * @see #fromJson(String, TypeToken) */ public T fromJson(String json, Class classOfT) throws JsonSyntaxException { - Object object = fromJson(json, (Type) classOfT); + T object = fromJson(json, TypeToken.get(classOfT)); return Primitives.wrap(classOfT).cast(object); } @@ -970,11 +970,9 @@ public T fromJson(String json, Class classOfT) throws JsonSyntaxException * a String, use {@link #fromJson(Reader, Type)} instead. * *

    Since {@code Type} is not parameterized by T, this method is not type-safe and - * should be used carefully. - * - *

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

    An exception is thrown if the JSON string has multiple top-level JSON elements, * or if there is trailing data. Use {@link #fromJson(JsonReader, Type)} if this behavior is @@ -1035,7 +1033,7 @@ public T fromJson(String json, TypeToken typeOfT) throws JsonSyntaxExcept * Therefore, this method should not be used if the desired type is a generic type. Note that * this method works fine if any of the fields of the specified object are generics, just the * object itself should not be a generic type. For the cases when the object is of generic type, - * invoke {@link #fromJson(Reader, Type)}. If you have the JSON in a String form instead of a + * invoke {@link #fromJson(Reader, TypeToken)}. If you have the JSON in a String form instead of a * {@link Reader}, use {@link #fromJson(String, Class)} instead. * *

    An exception is thrown if the JSON data has multiple top-level JSON elements, or if there @@ -1050,10 +1048,10 @@ public T fromJson(String json, TypeToken typeOfT) throws JsonSyntaxExcept * @since 1.2 * * @see #fromJson(String, Class) - * @see #fromJson(Reader, Type) + * @see #fromJson(Reader, TypeToken) */ public T fromJson(Reader json, Class classOfT) throws JsonSyntaxException, JsonIOException { - Object object = fromJson(json, (Type) classOfT); + T object = fromJson(json, TypeToken.get(classOfT)); return Primitives.wrap(classOfT).cast(object); } @@ -1064,11 +1062,9 @@ public T fromJson(Reader json, Class classOfT) throws JsonSyntaxException * String form instead of a {@link Reader}, use {@link #fromJson(String, Type)} instead. * *

    Since {@code Type} is not parameterized by T, this method is not type-safe and - * should be used carefully. - * - *

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

    An exception is thrown if the JSON data has multiple top-level JSON elements, or if there * is trailing data. Use {@link #fromJson(JsonReader, Type)} if this behavior is not desired. @@ -1141,7 +1137,7 @@ private static void assertFullConsumption(Object obj, JsonReader reader) { * Therefore, this method should not be used if the desired type is a generic type. Note that * this method works fine if any of the fields of the specified object are generics, just the * object itself should not be a generic type. For the cases when the object is of generic type, - * invoke {@link #fromJson(JsonReader, Type)}. + * invoke {@link #fromJson(JsonReader, TypeToken)}. * * @param the type of the desired object * @param reader the reader whose next JSON value should be deserialized @@ -1151,10 +1147,10 @@ private static void assertFullConsumption(Object obj, JsonReader reader) { * @throws JsonSyntaxException if json is not a valid representation for an object of type classOfT * * @see #fromJson(Reader, Class) - * @see #fromJson(JsonReader, Type) + * @see #fromJson(JsonReader, TypeToken) */ public T fromJson(JsonReader reader, Class classOfT) throws JsonIOException, JsonSyntaxException { - Object object = fromJson(reader, (Type) classOfT); + T object = fromJson(reader, TypeToken.get(classOfT)); return Primitives.wrap(classOfT).cast(object); } @@ -1165,11 +1161,9 @@ public T fromJson(JsonReader reader, Class classOfT) throws JsonIOExcepti * use {@link #fromJson(JsonReader, Class)} instead. * *

    Since {@code Type} is not parameterized by T, this method is not type-safe and - * should be used carefully. - * - *

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

    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. @@ -1212,7 +1206,7 @@ public T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, J * @throws JsonIOException if there was a problem reading from the JsonReader * @throws JsonSyntaxException if json is not a valid representation for an object of the type typeOfT * - * @see #fromJson(Reader, Type) + * @see #fromJson(Reader, TypeToken) * @see #fromJson(JsonReader, Class) */ public T fromJson(JsonReader reader, TypeToken typeOfT) throws JsonIOException, JsonSyntaxException { @@ -1255,7 +1249,7 @@ public T fromJson(JsonReader reader, TypeToken typeOfT) throws JsonIOExce * Therefore, this method should not be used if the desired type is a generic type. Note that * this method works fine if any of the fields of the specified object are generics, just the * object itself should not be a generic type. For the cases when the object is of generic type, - * invoke {@link #fromJson(JsonElement, Type)}. + * invoke {@link #fromJson(JsonElement, TypeToken)}. * * @param the type of the desired object * @param json the root of the parse tree of {@link JsonElement}s from which the object is to @@ -1267,10 +1261,10 @@ public T fromJson(JsonReader reader, TypeToken typeOfT) throws JsonIOExce * @since 1.3 * * @see #fromJson(Reader, Class) - * @see #fromJson(JsonElement, Type) + * @see #fromJson(JsonElement, TypeToken) */ public T fromJson(JsonElement json, Class classOfT) throws JsonSyntaxException { - Object object = fromJson(json, (Type) classOfT); + T object = fromJson(json, TypeToken.get(classOfT)); return Primitives.wrap(classOfT).cast(object); } @@ -1280,11 +1274,9 @@ public T fromJson(JsonElement json, Class classOfT) throws JsonSyntaxExce * non-generic objects, use {@link #fromJson(JsonElement, Class)} instead. * *

    Since {@code Type} is not parameterized by T, this method is not type-safe and - * should be used carefully. - * - *

    If you are creating the {@code Type} from a {@link TypeToken}, prefer using - * {@link #fromJson(JsonElement, TypeToken)} instead since its return type is based on the - * {@code TypeToken} and is therefore more type-safe. + * should be used carefully. If you are creating the {@code Type} from a {@link TypeToken}, + * prefer using {@link #fromJson(JsonElement, TypeToken)} instead since its return type is based + * on the {@code TypeToken} and is therefore more type-safe. * * @param the type of the desired object * @param json the root of the parse tree of {@link JsonElement}s from which the object is to @@ -1323,9 +1315,8 @@ public T fromJson(JsonElement json, Type typeOfT) throws JsonSyntaxException * @throws JsonSyntaxException if json is not a valid representation for an object of type typeOfT * @since 1.3 * - * @see #fromJson(Reader, Type) + * @see #fromJson(Reader, TypeToken) * @see #fromJson(JsonElement, Class) - * @see #fromJson(JsonElement, TypeToken) */ public T fromJson(JsonElement json, TypeToken typeOfT) throws JsonSyntaxException { if (json == null) { From 853d9f521f6999c3f0746a281f3433a4a8ed81a2 Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Fri, 16 Sep 2022 20:27:49 +0200 Subject: [PATCH 08/11] Extend documentation for fromJson(JsonReader, ...) --- gson/src/main/java/com/google/gson/Gson.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/gson/src/main/java/com/google/gson/Gson.java b/gson/src/main/java/com/google/gson/Gson.java index 83cb6aa9ea..a0c555c88d 100644 --- a/gson/src/main/java/com/google/gson/Gson.java +++ b/gson/src/main/java/com/google/gson/Gson.java @@ -1139,6 +1139,13 @@ private static void assertFullConsumption(Object obj, JsonReader reader) { * object itself should not be a generic type. For the cases when the object is of generic type, * invoke {@link #fromJson(JsonReader, TypeToken)}. * + *

    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. + * + *

    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. + * * @param the type of the desired object * @param reader the reader whose next JSON value should be deserialized * @param classOfT the class of T @@ -1194,6 +1201,13 @@ public T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, J * This method is useful if the specified object is a generic type. For non-generic objects, * use {@link #fromJson(JsonReader, Class)} instead. * + *

    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. + * + *

    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. + * * @param the type of the desired object * @param reader the reader whose next JSON value should be deserialized * @param typeOfT The specific genericized type of src. You should create an anonymous subclass of From c34ba6c96c7fb4dffb88005c493f5d54f4be91f2 Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Sun, 18 Sep 2022 18:24:27 +0200 Subject: [PATCH 09/11] Replace some TypeToken.getType() usages --- UserGuide.md | 4 ++-- .../metrics/CollectionsDeserializationBenchmark.java | 9 +++++---- .../java/com/google/gson/metrics/ParseBenchmark.java | 4 ++-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/UserGuide.md b/UserGuide.md index 12b53351bd..2aafb067e8 100644 --- a/UserGuide.md +++ b/UserGuide.md @@ -225,7 +225,7 @@ Collection ints = Arrays.asList(1,2,3,4,5); String json = gson.toJson(ints); // ==> json is [1,2,3,4,5] // Deserialization -Type collectionType = new TypeToken>(){}.getType(); +TypeToken> collectionType = new TypeToken>(){}; Collection ints2 = gson.fromJson(json, collectionType); // ==> ints2 is same as ints ``` @@ -263,7 +263,7 @@ For deserialization Gson uses the `read` method of the `TypeAdapter` registered ```java Gson gson = new Gson(); -Type mapType = new TypeToken>(){}.getType(); +TypeToken> mapType = new TypeToken>(){}; String json = "{\"key\": \"value\"}"; // Deserialization diff --git a/metrics/src/main/java/com/google/gson/metrics/CollectionsDeserializationBenchmark.java b/metrics/src/main/java/com/google/gson/metrics/CollectionsDeserializationBenchmark.java index dad0d99ae7..738b5ae4bf 100644 --- a/metrics/src/main/java/com/google/gson/metrics/CollectionsDeserializationBenchmark.java +++ b/metrics/src/main/java/com/google/gson/metrics/CollectionsDeserializationBenchmark.java @@ -33,14 +33,15 @@ */ public class CollectionsDeserializationBenchmark { - private static final Type LIST_TYPE = new TypeToken>(){}.getType(); + private static final TypeToken> LIST_TYPE_TOKEN = new TypeToken>(){}; + private static final Type LIST_TYPE = LIST_TYPE_TOKEN.getType(); private Gson gson; private String json; public static void main(String[] args) { NonUploadingCaliperRunner.run(CollectionsDeserializationBenchmark.class, args); } - + @BeforeExperiment void setUp() throws Exception { this.gson = new Gson(); @@ -51,12 +52,12 @@ void setUp() throws Exception { this.json = gson.toJson(bags, LIST_TYPE); } - /** + /** * Benchmark to measure Gson performance for deserializing an object */ public void timeCollectionsDefault(int reps) { for (int i=0; i() {}, new TypeReference() {}), READER_LONG(new TypeToken() {}, new TypeReference() {}); - private final Type gsonType; + private final TypeToken gsonType; private final TypeReference jacksonType; private Document(TypeToken typeToken, TypeReference typeReference) { - this.gsonType = typeToken.getType(); + this.gsonType = typeToken; this.jacksonType = typeReference; } } From 43ebe282a722355cafedd99c6450f74d2f043056 Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Sun, 18 Sep 2022 19:17:40 +0200 Subject: [PATCH 10/11] Address feedback; improve documentation --- gson/src/main/java/com/google/gson/Gson.java | 14 ++-- .../com/google/gson/reflect/TypeToken.java | 20 ++++- .../functional/ParameterizedTypesTest.java | 76 +++++++++++++++++-- 3 files changed, 96 insertions(+), 14 deletions(-) diff --git a/gson/src/main/java/com/google/gson/Gson.java b/gson/src/main/java/com/google/gson/Gson.java index a0c555c88d..080bff9015 100644 --- a/gson/src/main/java/com/google/gson/Gson.java +++ b/gson/src/main/java/com/google/gson/Gson.java @@ -80,11 +80,13 @@ * MyType target2 = gson.fromJson(json, MyType.class); // deserializes json into target2 * * - *

    If the object that your are serializing/deserializing is a {@code ParameterizedType} - * (i.e. contains at least one type parameter and may be an array) then you must use the - * {@link #toJson(Object, Type)} or {@link #fromJson(String, TypeToken)} method. Gson provides - * the {@link TypeToken} class which helps you with this. Here is an example showing how - * this can be done: + *

    If the type of the object that you are converting is a {@code ParameterizedType} + * (i.e. has at least one type argument, for example {@code List}) then for + * deserialization you must use a {@code fromJson} method with {@link Type} or {@link TypeToken} + * parameter to specify the parameterized type. For serialization specifying a {@code Type} + * or {@code TypeToken} is optional, otherwise Gson will use the runtime type of the object. + * {@link TypeToken} is a class provided by Gson which helps creating parameterized types. + * Here is an example showing how this can be done: *

      * TypeToken<List<MyType>> listType = new TypeToken<List<MyType>>() {};
      * List<MyType> target = new LinkedList<MyType>();
    @@ -92,7 +94,7 @@
      *
      * Gson gson = new Gson();
      * // For serialization you normally do not have to specify the type, Gson will use
    - * // the runtime class of the objects, however you can also specify it explicitly
    + * // the runtime type of the objects, however you can also specify it explicitly
      * String json = gson.toJson(target, listType.getType());
      *
      * // But for deserialization you have to specify the type
    diff --git a/gson/src/main/java/com/google/gson/reflect/TypeToken.java b/gson/src/main/java/com/google/gson/reflect/TypeToken.java
    index 547e5f5b5f..39e81f33f9 100644
    --- a/gson/src/main/java/com/google/gson/reflect/TypeToken.java
    +++ b/gson/src/main/java/com/google/gson/reflect/TypeToken.java
    @@ -32,7 +32,7 @@
      * runtime.
      *
      * 

    For example, to create a type literal for {@code List}, you can - * create an empty anonymous inner class: + * create an empty anonymous class: * *

    * {@code TypeToken> list = new TypeToken>() {};} @@ -43,6 +43,11 @@ * might expect, which gives a false sense of type-safety at compilation time * and can lead to an unexpected {@code ClassCastException} at runtime. * + *

    If the type arguments of the parameterized type are only available at + * runtime, for example when you want to create a {@code List} based on + * a {@code Class} representing the element type, the method + * {@link #getParameterized(Type, Type...)} can be used. + * * @author Bob Lee * @author Sven Mawson * @author Jesse Wilson @@ -317,8 +322,17 @@ public static TypeToken get(Class type) { } /** - * Gets type literal for the parameterized type represented by applying {@code typeArguments} to - * {@code rawType}. + * Gets a type literal for the parameterized type represented by applying {@code typeArguments} to + * {@code rawType}. This is mainly intended for situations where the type arguments are not + * available at compile time. The following example shows how a type token for {@code Map} + * can be created: + *

    {@code
    +   * Class keyClass = ...;
    +   * Class valueClass = ...;
    +   * TypeToken mapTypeToken = TypeToken.getParameterized(Map.class, keyClass, valueClass);
    +   * }
    + * As seen here the result is a {@code TypeToken}; this method cannot provide any type safety, + * and care must be taken to pass in the correct number of type arguments. * * @throws IllegalArgumentException * If {@code rawType} is not of type {@code Class}, or if the type arguments are invalid for diff --git a/gson/src/test/java/com/google/gson/functional/ParameterizedTypesTest.java b/gson/src/test/java/com/google/gson/functional/ParameterizedTypesTest.java index 49cb0db9bc..e616874620 100644 --- a/gson/src/test/java/com/google/gson/functional/ParameterizedTypesTest.java +++ b/gson/src/test/java/com/google/gson/functional/ParameterizedTypesTest.java @@ -16,13 +16,19 @@ package com.google.gson.functional; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; import com.google.gson.ParameterizedTypeFixtures.MyParameterizedType; import com.google.gson.ParameterizedTypeFixtures.MyParameterizedTypeAdapter; import com.google.gson.ParameterizedTypeFixtures.MyParameterizedTypeInstanceCreator; import com.google.gson.common.TestTypes.BagOfPrimitives; import com.google.gson.reflect.TypeToken; +import com.google.gson.stream.JsonReader; import java.io.Reader; import java.io.Serializable; import java.io.StringReader; @@ -32,7 +38,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import junit.framework.TestCase; +import org.junit.Before; +import org.junit.Test; /** * Functional tests for the serialization and deserialization of parameterized types in Gson. @@ -40,15 +47,15 @@ * @author Inderjeet Singh * @author Joel Leitch */ -public class ParameterizedTypesTest extends TestCase { +public class ParameterizedTypesTest { private Gson gson; - @Override - protected void setUp() throws Exception { - super.setUp(); + @Before + public void setUp() { gson = new Gson(); } + @Test public void testParameterizedTypesSerialization() throws Exception { MyParameterizedType src = new MyParameterizedType<>(10); Type typeOfSrc = new TypeToken>() {}.getType(); @@ -56,6 +63,7 @@ public void testParameterizedTypesSerialization() throws Exception { assertEquals(src.getExpectedJson(), json); } + @Test public void testParameterizedTypeDeserialization() throws Exception { BagOfPrimitives bag = new BagOfPrimitives(); MyParameterizedType expected = new MyParameterizedType<>(bag); @@ -70,6 +78,7 @@ public void testParameterizedTypeDeserialization() throws Exception { assertEquals(expected, actual); } + @Test public void testTypesWithMultipleParametersSerialization() throws Exception { MultiParameters src = new MultiParameters<>(10, 1.0F, 2.1D, "abc", new BagOfPrimitives()); @@ -81,6 +90,7 @@ public void testTypesWithMultipleParametersSerialization() throws Exception { assertEquals(expected, json); } + @Test public void testTypesWithMultipleParametersDeserialization() throws Exception { Type typeOfTarget = new TypeToken>() {}.getType(); @@ -93,6 +103,7 @@ public void testTypesWithMultipleParametersDeserialization() throws Exception { assertEquals(expected, target); } + @Test public void testParameterizedTypeWithCustomSerializer() { Type ptIntegerType = new TypeToken>() {}.getType(); Type ptStringType = new TypeToken>() {}.getType(); @@ -109,6 +120,7 @@ public void testParameterizedTypeWithCustomSerializer() { assertEquals(MyParameterizedTypeAdapter.getExpectedJson(stringTarget), json); } + @Test public void testParameterizedTypesWithCustomDeserializer() { Type ptIntegerType = new TypeToken>() {}.getType(); Type ptStringType = new TypeToken>() {}.getType(); @@ -130,6 +142,7 @@ public void testParameterizedTypesWithCustomDeserializer() { assertEquals("abc", stringTarget.value); } + @Test public void testParameterizedTypesWithWriterSerialization() throws Exception { Writer writer = new StringWriter(); MyParameterizedType src = new MyParameterizedType<>(10); @@ -138,6 +151,7 @@ public void testParameterizedTypesWithWriterSerialization() throws Exception { assertEquals(src.getExpectedJson(), writer.toString()); } + @Test public void testParameterizedTypeWithReaderDeserialization() throws Exception { BagOfPrimitives bag = new BagOfPrimitives(); MyParameterizedType expected = new MyParameterizedType<>(bag); @@ -158,6 +172,7 @@ private static T[] arrayOf(T... args) { return args; } + @Test public void testVariableTypeFieldsAndGenericArraysSerialization() throws Exception { Integer obj = 0; Integer[] array = { 1, 2, 3 }; @@ -174,6 +189,7 @@ public void testVariableTypeFieldsAndGenericArraysSerialization() throws Excepti assertEquals(objToSerialize.getExpectedJson(), json); } + @Test public void testVariableTypeFieldsAndGenericArraysDeserialization() throws Exception { Integer obj = 0; Integer[] array = { 1, 2, 3 }; @@ -191,6 +207,7 @@ public void testVariableTypeFieldsAndGenericArraysDeserialization() throws Excep assertEquals(objAfterDeserialization.getExpectedJson(), json); } + @Test public void testVariableTypeDeserialization() throws Exception { Type typeOfSrc = new TypeToken>() {}.getType(); ObjectWithTypeVariables objToSerialize = @@ -201,6 +218,7 @@ public void testVariableTypeDeserialization() throws Exception { assertEquals(objAfterDeserialization.getExpectedJson(), json); } + @Test public void testVariableTypeArrayDeserialization() throws Exception { Integer[] array = { 1, 2, 3 }; @@ -213,6 +231,7 @@ public void testVariableTypeArrayDeserialization() throws Exception { assertEquals(objAfterDeserialization.getExpectedJson(), json); } + @Test public void testParameterizedTypeWithVariableTypeDeserialization() throws Exception { List list = new ArrayList<>(); list.add(4); @@ -227,6 +246,7 @@ public void testParameterizedTypeWithVariableTypeDeserialization() throws Except assertEquals(objAfterDeserialization.getExpectedJson(), json); } + @Test public void testParameterizedTypeGenericArraysSerialization() throws Exception { List list = new ArrayList<>(); list.add(1); @@ -240,6 +260,7 @@ public void testParameterizedTypeGenericArraysSerialization() throws Exception { assertEquals("{\"arrayOfListOfTypeParameters\":[[1,2],[1,2]]}", json); } + @Test public void testParameterizedTypeGenericArraysDeserialization() throws Exception { List list = new ArrayList<>(); list.add(1); @@ -483,6 +504,7 @@ public static final class Amount int value = 30; } + @Test public void testDeepParameterizedTypeSerialization() { Amount amount = new Amount<>(); String json = gson.toJson(amount); @@ -490,6 +512,7 @@ public void testDeepParameterizedTypeSerialization() { assertTrue(json.contains("30")); } + @Test public void testDeepParameterizedTypeDeserialization() { String json = "{value:30}"; Type type = new TypeToken>() {}.getType(); @@ -497,4 +520,47 @@ public void testDeepParameterizedTypeDeserialization() { assertEquals(30, amount.value); } // End: tests to reproduce issue 103 + + private static void assertCorrectlyDeserialized(Object object) { + @SuppressWarnings("unchecked") + List list = (List) object; + assertEquals(1, list.size()); + assertEquals(4, list.get(0).q); + } + + @Test + public void testGsonFromJsonTypeToken() { + TypeToken> typeToken = new TypeToken>() {}; + Type type = typeToken.getType(); + + { + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("q", 4); + JsonArray jsonArray = new JsonArray(); + jsonArray.add(jsonObject); + + assertCorrectlyDeserialized(gson.fromJson(jsonArray, typeToken)); + assertCorrectlyDeserialized(gson.fromJson(jsonArray, type)); + } + + String json = "[{\"q\":4}]"; + + { + assertCorrectlyDeserialized(gson.fromJson(json, typeToken)); + assertCorrectlyDeserialized(gson.fromJson(json, type)); + } + + { + assertCorrectlyDeserialized(gson.fromJson(new StringReader(json), typeToken)); + assertCorrectlyDeserialized(gson.fromJson(new StringReader(json), type)); + } + + { + JsonReader reader = new JsonReader(new StringReader(json)); + assertCorrectlyDeserialized(gson.fromJson(reader, typeToken)); + + reader = new JsonReader(new StringReader(json)); + assertCorrectlyDeserialized(gson.fromJson(reader, type)); + } + } } From 6ad87f033fb24d91575a51c99786a33d27bbfd3d Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Mon, 19 Sep 2022 02:02:49 +0200 Subject: [PATCH 11/11] Remove fromJson(JsonReader, Class) again As noticed during review adding this method is source incompatible. --- gson/src/main/java/com/google/gson/Gson.java | 48 ++++---------------- 1 file changed, 9 insertions(+), 39 deletions(-) diff --git a/gson/src/main/java/com/google/gson/Gson.java b/gson/src/main/java/com/google/gson/Gson.java index 080bff9015..c3262a6fe0 100644 --- a/gson/src/main/java/com/google/gson/Gson.java +++ b/gson/src/main/java/com/google/gson/Gson.java @@ -947,7 +947,7 @@ public void toJson(JsonElement jsonElement, JsonWriter writer) throws JsonIOExce * a String, use {@link #fromJson(Reader, Class)} instead. * *

    An exception is thrown if the JSON string has multiple top-level JSON elements, or if there - * is trailing data. Use {@link #fromJson(JsonReader, Class)} if this behavior is not desired. + * is trailing data. Use {@link #fromJson(JsonReader, Type)} if this behavior is not desired. * * @param the type of the desired object * @param json the string from which the object is to be deserialized @@ -1039,7 +1039,7 @@ public T fromJson(String json, TypeToken typeOfT) throws JsonSyntaxExcept * {@link Reader}, use {@link #fromJson(String, Class)} instead. * *

    An exception is thrown if the JSON data has multiple top-level JSON elements, or if there - * is trailing data. Use {@link #fromJson(JsonReader, Class)} if this behavior is not desired. + * is trailing data. Use {@link #fromJson(JsonReader, Type)} if this behavior is not desired. * * @param the type of the desired object * @param json the reader producing the JSON from which the object is to be deserialized. @@ -1131,48 +1131,18 @@ private static void assertFullConsumption(Object obj, JsonReader reader) { } } - /** - * Reads the next JSON value from {@code reader} and converts it to an object - * of type {@code classOfT}. Returns {@code null}, if the {@code reader} is at EOF. - * It is not suitable to use if the specified class is a generic type since it - * will not have the generic type information because of the Type Erasure feature of Java. - * Therefore, this method should not be used if the desired type is a generic type. Note that - * this method works fine if any of the fields of the specified object are generics, just the - * object itself should not be a generic type. For the cases when the object is of generic type, - * invoke {@link #fromJson(JsonReader, TypeToken)}. - * - *

    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. - * - *

    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. - * - * @param the type of the desired object - * @param reader the reader whose next JSON value should be deserialized - * @param classOfT the class of T - * @return an object of type T from the JsonReader. Returns {@code null} if {@code reader} is at EOF. - * @throws JsonIOException if there was a problem reading from the JsonReader - * @throws JsonSyntaxException if json is not a valid representation for an object of type classOfT - * - * @see #fromJson(Reader, Class) - * @see #fromJson(JsonReader, TypeToken) - */ - public T fromJson(JsonReader reader, Class classOfT) throws JsonIOException, JsonSyntaxException { - T object = fromJson(reader, TypeToken.get(classOfT)); - return Primitives.wrap(classOfT).cast(object); - } + // fromJson(JsonReader, Class) is unfortunately missing and cannot be added now without breaking + // source compatibility in certain cases, see https://github.com/google/gson/pull/1700#discussion_r973764414 /** * Reads the next JSON value from {@code reader} and converts it to an object * of type {@code typeOfT}. Returns {@code null}, if the {@code reader} is at EOF. - * This method is useful if the specified object is a generic type. For non-generic objects, - * use {@link #fromJson(JsonReader, Class)} instead. * *

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

    Unlike the other {@code fromJson} methods, no exception is thrown if the JSON data has * multiple top-level JSON elements, or if there is trailing data. @@ -1189,7 +1159,6 @@ public T fromJson(JsonReader reader, Class classOfT) throws JsonIOExcepti * @throws JsonSyntaxException if json is not a valid representation for an object of type typeOfT * * @see #fromJson(Reader, Type) - * @see #fromJson(JsonReader, Class) * @see #fromJson(JsonReader, TypeToken) */ @SuppressWarnings("unchecked") @@ -1201,7 +1170,8 @@ public T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, J * Reads the next JSON value from {@code reader} and converts it to an object * of type {@code typeOfT}. Returns {@code null}, if the {@code reader} is at EOF. * This method is useful if the specified object is a generic type. For non-generic objects, - * use {@link #fromJson(JsonReader, Class)} instead. + * {@link #fromJson(JsonReader, Type)} can be called, or {@link TypeToken#get(Class)} can + * be used to create the type token. * *

    Unlike the other {@code fromJson} methods, no exception is thrown if the JSON data has * multiple top-level JSON elements, or if there is trailing data. @@ -1223,7 +1193,7 @@ public T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, J * @throws JsonSyntaxException if json is not a valid representation for an object of the type typeOfT * * @see #fromJson(Reader, TypeToken) - * @see #fromJson(JsonReader, Class) + * @see #fromJson(JsonReader, Type) */ public T fromJson(JsonReader reader, TypeToken typeOfT) throws JsonIOException, JsonSyntaxException { boolean isEmpty = true;