Skip to content

Commit 05e6558

Browse files
committed
Address feedback; improve documentation
1 parent c34ba6c commit 05e6558

File tree

3 files changed

+96
-14
lines changed

3 files changed

+96
-14
lines changed

gson/src/main/java/com/google/gson/Gson.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -80,19 +80,21 @@
8080
* MyType target2 = gson.fromJson(json, MyType.class); // deserializes json into target2
8181
* </pre>
8282
*
83-
* <p>If the object that your are serializing/deserializing is a {@code ParameterizedType}
84-
* (i.e. contains at least one type parameter and may be an array) then you must use the
85-
* {@link #toJson(Object, Type)} or {@link #fromJson(String, TypeToken)} method. Gson provides
86-
* the {@link TypeToken} class which helps you with this. Here is an example showing how
87-
* this can be done:
83+
* <p>If the type of the object that you are converting is a {@code ParameterizedType}
84+
* (i.e. has at least one type argument, for example {@code List<MyType>}) then for
85+
* deserialization you must use a {@code fromJson} method with {@link Type} or {@link TypeToken}
86+
* parameter to specify the parameterized type. For serialization you can specify a {@code Type}
87+
* or {@code TypeToken}, otherwise Gson will use the runtime type of the object.
88+
* {@link TypeToken} is a class provided by Gson which helps creating parameterized types.
89+
* Here is an example showing how this can be done:
8890
* <pre>
8991
* TypeToken&lt;List&lt;MyType&gt;&gt; listType = new TypeToken&lt;List&lt;MyType&gt;&gt;() {};
9092
* List&lt;MyType&gt; target = new LinkedList&lt;MyType&gt;();
9193
* target.add(new MyType(1, "abc"));
9294
*
9395
* Gson gson = new Gson();
9496
* // For serialization you normally do not have to specify the type, Gson will use
95-
* // the runtime class of the objects, however you can also specify it explicitly
97+
* // the runtime type of the objects, however you can also specify it explicitly
9698
* String json = gson.toJson(target, listType.getType());
9799
*
98100
* // But for deserialization you have to specify the type

gson/src/main/java/com/google/gson/reflect/TypeToken.java

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
* runtime.
3333
*
3434
* <p>For example, to create a type literal for {@code List<String>}, you can
35-
* create an empty anonymous inner class:
35+
* create an empty anonymous class:
3636
*
3737
* <p>
3838
* {@code TypeToken<List<String>> list = new TypeToken<List<String>>() {};}
@@ -43,6 +43,11 @@
4343
* might expect, which gives a false sense of type-safety at compilation time
4444
* and can lead to an unexpected {@code ClassCastException} at runtime.
4545
*
46+
* <p>If the type arguments of the parameterized type are only available at
47+
* runtime, for example when you want to create a {@code List<E>} based on
48+
* a {@code Class<E>} representing the element type, the method
49+
* {@link #getParameterized(Type, Type...)} can be used.
50+
*
4651
* @author Bob Lee
4752
* @author Sven Mawson
4853
* @author Jesse Wilson
@@ -317,8 +322,17 @@ public static <T> TypeToken<T> get(Class<T> type) {
317322
}
318323

319324
/**
320-
* Gets type literal for the parameterized type represented by applying {@code typeArguments} to
321-
* {@code rawType}.
325+
* Gets a type literal for the parameterized type represented by applying {@code typeArguments} to
326+
* {@code rawType}. This is mainly intended for situations where the type arguments are not
327+
* available at compile time. The following example shows how a type token for {@code Map<K, V>}
328+
* can be created:
329+
* <pre>{@code
330+
* Class<K> keyClass = ...;
331+
* Class<V> valueClass = ...;
332+
* TypeToken<?> mapTypeToken = TypeToken.getParameterized(Map.class, keyClass, valueClass);
333+
* }</pre>
334+
* As seen here the result is a {@code TypeToken<?>}; this method cannot provide any type safety,
335+
* and care must be taken to pass in the correct number of type arguments.
322336
*
323337
* @throws IllegalArgumentException
324338
* If {@code rawType} is not of type {@code Class}, or if the type arguments are invalid for

gson/src/test/java/com/google/gson/functional/ParameterizedTypesTest.java

Lines changed: 71 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,19 @@
1616

1717
package com.google.gson.functional;
1818

19+
import static org.junit.Assert.assertEquals;
20+
import static org.junit.Assert.assertTrue;
21+
1922
import com.google.gson.Gson;
2023
import com.google.gson.GsonBuilder;
24+
import com.google.gson.JsonArray;
25+
import com.google.gson.JsonObject;
2126
import com.google.gson.ParameterizedTypeFixtures.MyParameterizedType;
2227
import com.google.gson.ParameterizedTypeFixtures.MyParameterizedTypeAdapter;
2328
import com.google.gson.ParameterizedTypeFixtures.MyParameterizedTypeInstanceCreator;
2429
import com.google.gson.common.TestTypes.BagOfPrimitives;
2530
import com.google.gson.reflect.TypeToken;
31+
import com.google.gson.stream.JsonReader;
2632
import java.io.Reader;
2733
import java.io.Serializable;
2834
import java.io.StringReader;
@@ -32,30 +38,32 @@
3238
import java.util.ArrayList;
3339
import java.util.Arrays;
3440
import java.util.List;
35-
import junit.framework.TestCase;
41+
import org.junit.Before;
42+
import org.junit.Test;
3643

3744
/**
3845
* Functional tests for the serialization and deserialization of parameterized types in Gson.
3946
*
4047
* @author Inderjeet Singh
4148
* @author Joel Leitch
4249
*/
43-
public class ParameterizedTypesTest extends TestCase {
50+
public class ParameterizedTypesTest {
4451
private Gson gson;
4552

46-
@Override
47-
protected void setUp() throws Exception {
48-
super.setUp();
53+
@Before
54+
public void setUp() {
4955
gson = new Gson();
5056
}
5157

58+
@Test
5259
public void testParameterizedTypesSerialization() throws Exception {
5360
MyParameterizedType<Integer> src = new MyParameterizedType<>(10);
5461
Type typeOfSrc = new TypeToken<MyParameterizedType<Integer>>() {}.getType();
5562
String json = gson.toJson(src, typeOfSrc);
5663
assertEquals(src.getExpectedJson(), json);
5764
}
5865

66+
@Test
5967
public void testParameterizedTypeDeserialization() throws Exception {
6068
BagOfPrimitives bag = new BagOfPrimitives();
6169
MyParameterizedType<BagOfPrimitives> expected = new MyParameterizedType<>(bag);
@@ -70,6 +78,7 @@ public void testParameterizedTypeDeserialization() throws Exception {
7078
assertEquals(expected, actual);
7179
}
7280

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

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

106+
@Test
96107
public void testParameterizedTypeWithCustomSerializer() {
97108
Type ptIntegerType = new TypeToken<MyParameterizedType<Integer>>() {}.getType();
98109
Type ptStringType = new TypeToken<MyParameterizedType<String>>() {}.getType();
@@ -109,6 +120,7 @@ public void testParameterizedTypeWithCustomSerializer() {
109120
assertEquals(MyParameterizedTypeAdapter.<String>getExpectedJson(stringTarget), json);
110121
}
111122

123+
@Test
112124
public void testParameterizedTypesWithCustomDeserializer() {
113125
Type ptIntegerType = new TypeToken<MyParameterizedType<Integer>>() {}.getType();
114126
Type ptStringType = new TypeToken<MyParameterizedType<String>>() {}.getType();
@@ -130,6 +142,7 @@ public void testParameterizedTypesWithCustomDeserializer() {
130142
assertEquals("abc", stringTarget.value);
131143
}
132144

145+
@Test
133146
public void testParameterizedTypesWithWriterSerialization() throws Exception {
134147
Writer writer = new StringWriter();
135148
MyParameterizedType<Integer> src = new MyParameterizedType<>(10);
@@ -138,6 +151,7 @@ public void testParameterizedTypesWithWriterSerialization() throws Exception {
138151
assertEquals(src.getExpectedJson(), writer.toString());
139152
}
140153

154+
@Test
141155
public void testParameterizedTypeWithReaderDeserialization() throws Exception {
142156
BagOfPrimitives bag = new BagOfPrimitives();
143157
MyParameterizedType<BagOfPrimitives> expected = new MyParameterizedType<>(bag);
@@ -158,6 +172,7 @@ private static <T> T[] arrayOf(T... args) {
158172
return args;
159173
}
160174

175+
@Test
161176
public void testVariableTypeFieldsAndGenericArraysSerialization() throws Exception {
162177
Integer obj = 0;
163178
Integer[] array = { 1, 2, 3 };
@@ -174,6 +189,7 @@ public void testVariableTypeFieldsAndGenericArraysSerialization() throws Excepti
174189
assertEquals(objToSerialize.getExpectedJson(), json);
175190
}
176191

192+
@Test
177193
public void testVariableTypeFieldsAndGenericArraysDeserialization() throws Exception {
178194
Integer obj = 0;
179195
Integer[] array = { 1, 2, 3 };
@@ -191,6 +207,7 @@ public void testVariableTypeFieldsAndGenericArraysDeserialization() throws Excep
191207
assertEquals(objAfterDeserialization.getExpectedJson(), json);
192208
}
193209

210+
@Test
194211
public void testVariableTypeDeserialization() throws Exception {
195212
Type typeOfSrc = new TypeToken<ObjectWithTypeVariables<Integer>>() {}.getType();
196213
ObjectWithTypeVariables<Integer> objToSerialize =
@@ -201,6 +218,7 @@ public void testVariableTypeDeserialization() throws Exception {
201218
assertEquals(objAfterDeserialization.getExpectedJson(), json);
202219
}
203220

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

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

234+
@Test
216235
public void testParameterizedTypeWithVariableTypeDeserialization() throws Exception {
217236
List<Integer> list = new ArrayList<>();
218237
list.add(4);
@@ -227,6 +246,7 @@ public void testParameterizedTypeWithVariableTypeDeserialization() throws Except
227246
assertEquals(objAfterDeserialization.getExpectedJson(), json);
228247
}
229248

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

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

507+
@Test
486508
public void testDeepParameterizedTypeSerialization() {
487509
Amount<MyQuantity> amount = new Amount<>();
488510
String json = gson.toJson(amount);
489511
assertTrue(json.contains("value"));
490512
assertTrue(json.contains("30"));
491513
}
492514

515+
@Test
493516
public void testDeepParameterizedTypeDeserialization() {
494517
String json = "{value:30}";
495518
Type type = new TypeToken<Amount<MyQuantity>>() {}.getType();
496519
Amount<MyQuantity> amount = gson.fromJson(json, type);
497520
assertEquals(30, amount.value);
498521
}
499522
// End: tests to reproduce issue 103
523+
524+
private static void assertCorrectlyDeserialized(Object object) {
525+
@SuppressWarnings("unchecked")
526+
List<Quantity> list = (List<Quantity>) object;
527+
assertEquals(1, list.size());
528+
assertEquals(4, list.get(0).q);
529+
}
530+
531+
@Test
532+
public void testGsonFromJsonTypeToken() {
533+
TypeToken<List<Quantity>> typeToken = new TypeToken<List<Quantity>>() {};
534+
Type type = typeToken.getType();
535+
536+
{
537+
JsonObject jsonObject = new JsonObject();
538+
jsonObject.addProperty("q", 4);
539+
JsonArray jsonArray = new JsonArray();
540+
jsonArray.add(jsonObject);
541+
542+
assertCorrectlyDeserialized(gson.fromJson(jsonArray, typeToken));
543+
assertCorrectlyDeserialized(gson.fromJson(jsonArray, type));
544+
}
545+
546+
String json = "[{\"q\":4}]";
547+
548+
{
549+
assertCorrectlyDeserialized(gson.fromJson(json, typeToken));
550+
assertCorrectlyDeserialized(gson.fromJson(json, type));
551+
}
552+
553+
{
554+
assertCorrectlyDeserialized(gson.fromJson(new StringReader(json), typeToken));
555+
assertCorrectlyDeserialized(gson.fromJson(new StringReader(json), type));
556+
}
557+
558+
{
559+
JsonReader reader = new JsonReader(new StringReader(json));
560+
assertCorrectlyDeserialized(gson.fromJson(reader, typeToken));
561+
562+
reader = new JsonReader(new StringReader(json));
563+
assertCorrectlyDeserialized(gson.fromJson(reader, type));
564+
}
565+
}
500566
}

0 commit comments

Comments
 (0)