Skip to content

Commit

Permalink
Address feedback; improve documentation
Browse files Browse the repository at this point in the history
  • Loading branch information
Marcono1234 committed Sep 18, 2022
1 parent c34ba6c commit 43ebe28
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 14 deletions.
14 changes: 8 additions & 6 deletions gson/src/main/java/com/google/gson/Gson.java
Expand Up @@ -80,19 +80,21 @@
* MyType target2 = gson.fromJson(json, MyType.class); // deserializes json into target2
* </pre>
*
* <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, TypeToken)} method. Gson provides
* the {@link TypeToken} class which helps you with this. Here is an example showing how
* this can be done:
* <p>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<MyType>}) 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:
* <pre>
* TypeToken&lt;List&lt;MyType&gt;&gt; listType = new TypeToken&lt;List&lt;MyType&gt;&gt;() {};
* List&lt;MyType&gt; target = new LinkedList&lt;MyType&gt;();
* target.add(new MyType(1, "abc"));
*
* Gson gson = new Gson();
* // For serialization you normally do not have to specify the type, Gson will use
* // the runtime 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
Expand Down
20 changes: 17 additions & 3 deletions gson/src/main/java/com/google/gson/reflect/TypeToken.java
Expand Up @@ -32,7 +32,7 @@
* runtime.
*
* <p>For example, to create a type literal for {@code List<String>}, you can
* create an empty anonymous inner class:
* create an empty anonymous class:
*
* <p>
* {@code TypeToken<List<String>> list = new TypeToken<List<String>>() {};}
Expand All @@ -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.
*
* <p>If the type arguments of the parameterized type are only available at
* runtime, for example when you want to create a {@code List<E>} based on
* a {@code Class<E>} representing the element type, the method
* {@link #getParameterized(Type, Type...)} can be used.
*
* @author Bob Lee
* @author Sven Mawson
* @author Jesse Wilson
Expand Down Expand Up @@ -317,8 +322,17 @@ public static <T> TypeToken<T> get(Class<T> 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<K, V>}
* can be created:
* <pre>{@code
* Class<K> keyClass = ...;
* Class<V> valueClass = ...;
* TypeToken<?> mapTypeToken = TypeToken.getParameterized(Map.class, keyClass, valueClass);
* }</pre>
* 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
Expand Down
Expand Up @@ -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;
Expand All @@ -32,30 +38,32 @@
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.
*
* @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<Integer> src = new MyParameterizedType<>(10);
Type typeOfSrc = new TypeToken<MyParameterizedType<Integer>>() {}.getType();
String json = gson.toJson(src, typeOfSrc);
assertEquals(src.getExpectedJson(), json);
}

@Test
public void testParameterizedTypeDeserialization() throws Exception {
BagOfPrimitives bag = new BagOfPrimitives();
MyParameterizedType<BagOfPrimitives> expected = new MyParameterizedType<>(bag);
Expand All @@ -70,6 +78,7 @@ public void testParameterizedTypeDeserialization() throws Exception {
assertEquals(expected, actual);
}

@Test
public void testTypesWithMultipleParametersSerialization() throws Exception {
MultiParameters<Integer, Float, Double, String, BagOfPrimitives> src =
new MultiParameters<>(10, 1.0F, 2.1D, "abc", new BagOfPrimitives());
Expand All @@ -81,6 +90,7 @@ public void testTypesWithMultipleParametersSerialization() throws Exception {
assertEquals(expected, json);
}

@Test
public void testTypesWithMultipleParametersDeserialization() throws Exception {
Type typeOfTarget = new TypeToken<MultiParameters<Integer, Float, Double, String,
BagOfPrimitives>>() {}.getType();
Expand All @@ -93,6 +103,7 @@ public void testTypesWithMultipleParametersDeserialization() throws Exception {
assertEquals(expected, target);
}

@Test
public void testParameterizedTypeWithCustomSerializer() {
Type ptIntegerType = new TypeToken<MyParameterizedType<Integer>>() {}.getType();
Type ptStringType = new TypeToken<MyParameterizedType<String>>() {}.getType();
Expand All @@ -109,6 +120,7 @@ public void testParameterizedTypeWithCustomSerializer() {
assertEquals(MyParameterizedTypeAdapter.<String>getExpectedJson(stringTarget), json);
}

@Test
public void testParameterizedTypesWithCustomDeserializer() {
Type ptIntegerType = new TypeToken<MyParameterizedType<Integer>>() {}.getType();
Type ptStringType = new TypeToken<MyParameterizedType<String>>() {}.getType();
Expand All @@ -130,6 +142,7 @@ public void testParameterizedTypesWithCustomDeserializer() {
assertEquals("abc", stringTarget.value);
}

@Test
public void testParameterizedTypesWithWriterSerialization() throws Exception {
Writer writer = new StringWriter();
MyParameterizedType<Integer> src = new MyParameterizedType<>(10);
Expand All @@ -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<BagOfPrimitives> expected = new MyParameterizedType<>(bag);
Expand All @@ -158,6 +172,7 @@ private static <T> T[] arrayOf(T... args) {
return args;
}

@Test
public void testVariableTypeFieldsAndGenericArraysSerialization() throws Exception {
Integer obj = 0;
Integer[] array = { 1, 2, 3 };
Expand All @@ -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 };
Expand All @@ -191,6 +207,7 @@ public void testVariableTypeFieldsAndGenericArraysDeserialization() throws Excep
assertEquals(objAfterDeserialization.getExpectedJson(), json);
}

@Test
public void testVariableTypeDeserialization() throws Exception {
Type typeOfSrc = new TypeToken<ObjectWithTypeVariables<Integer>>() {}.getType();
ObjectWithTypeVariables<Integer> objToSerialize =
Expand All @@ -201,6 +218,7 @@ public void testVariableTypeDeserialization() throws Exception {
assertEquals(objAfterDeserialization.getExpectedJson(), json);
}

@Test
public void testVariableTypeArrayDeserialization() throws Exception {
Integer[] array = { 1, 2, 3 };

Expand All @@ -213,6 +231,7 @@ public void testVariableTypeArrayDeserialization() throws Exception {
assertEquals(objAfterDeserialization.getExpectedJson(), json);
}

@Test
public void testParameterizedTypeWithVariableTypeDeserialization() throws Exception {
List<Integer> list = new ArrayList<>();
list.add(4);
Expand All @@ -227,6 +246,7 @@ public void testParameterizedTypeWithVariableTypeDeserialization() throws Except
assertEquals(objAfterDeserialization.getExpectedJson(), json);
}

@Test
public void testParameterizedTypeGenericArraysSerialization() throws Exception {
List<Integer> list = new ArrayList<>();
list.add(1);
Expand All @@ -240,6 +260,7 @@ public void testParameterizedTypeGenericArraysSerialization() throws Exception {
assertEquals("{\"arrayOfListOfTypeParameters\":[[1,2],[1,2]]}", json);
}

@Test
public void testParameterizedTypeGenericArraysDeserialization() throws Exception {
List<Integer> list = new ArrayList<>();
list.add(1);
Expand Down Expand Up @@ -483,18 +504,63 @@ public static final class Amount<Q extends Quantity>
int value = 30;
}

@Test
public void testDeepParameterizedTypeSerialization() {
Amount<MyQuantity> amount = new Amount<>();
String json = gson.toJson(amount);
assertTrue(json.contains("value"));
assertTrue(json.contains("30"));
}

@Test
public void testDeepParameterizedTypeDeserialization() {
String json = "{value:30}";
Type type = new TypeToken<Amount<MyQuantity>>() {}.getType();
Amount<MyQuantity> amount = gson.fromJson(json, type);
assertEquals(30, amount.value);
}
// End: tests to reproduce issue 103

private static void assertCorrectlyDeserialized(Object object) {
@SuppressWarnings("unchecked")
List<Quantity> list = (List<Quantity>) object;
assertEquals(1, list.size());
assertEquals(4, list.get(0).q);
}

@Test
public void testGsonFromJsonTypeToken() {
TypeToken<List<Quantity>> typeToken = new TypeToken<List<Quantity>>() {};
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));
}
}
}

0 comments on commit 43ebe28

Please sign in to comment.