1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.google.common.reflect;
18
19 import static com.google.common.truth.Truth.assertThat;
20 import static java.util.Arrays.asList;
21
22 import com.google.common.collect.Lists;
23 import com.google.common.testing.EqualsTester;
24 import com.google.common.testing.NullPointerTester;
25 import com.google.common.testing.NullPointerTester.Visibility;
26 import com.google.common.testing.SerializableTester;
27
28 import junit.framework.TestCase;
29
30 import java.lang.reflect.GenericArrayType;
31 import java.lang.reflect.GenericDeclaration;
32 import java.lang.reflect.ParameterizedType;
33 import java.lang.reflect.Type;
34 import java.lang.reflect.TypeVariable;
35 import java.lang.reflect.WildcardType;
36 import java.util.Arrays;
37 import java.util.HashMap;
38 import java.util.List;
39 import java.util.Map;
40
41
42
43
44
45
46 public class TypesTest extends TestCase {
47
48 public void testNewParameterizedType_ownerTypeImplied() throws Exception {
49 ParameterizedType jvmType = (ParameterizedType)
50 new TypeCapture<Map.Entry<String, Integer>>() {}.capture();
51 ParameterizedType ourType = Types.newParameterizedType(
52 Map.Entry.class, String.class, Integer.class);
53 assertEquals(jvmType, ourType);
54 assertEquals(Map.class, ourType.getOwnerType());
55 }
56
57 public void testNewParameterizedType() {
58 ParameterizedType jvmType = (ParameterizedType)
59 new TypeCapture<HashMap<String, int[][]>>() {}.capture();
60 ParameterizedType ourType = Types.newParameterizedType(
61 HashMap.class, String.class, int[][].class);
62
63 new EqualsTester()
64 .addEqualityGroup(jvmType, ourType)
65 .testEquals();
66 assertEquals(jvmType.toString(), ourType.toString());
67 assertEquals(jvmType.hashCode(), ourType.hashCode());
68 assertEquals(HashMap.class, ourType.getRawType());
69 assertThat(ourType.getActualTypeArguments()).asList()
70 .has().exactlyAs(asList(jvmType.getActualTypeArguments())).inOrder();
71 assertEquals(Arrays.asList(
72 String.class,
73 Types.newArrayType(Types.newArrayType(int.class))),
74 Arrays.asList(ourType.getActualTypeArguments()));
75 assertEquals(null, ourType.getOwnerType());
76 }
77
78 public void testNewParameterizedType_nonStaticLocalClass() {
79 class LocalClass<T> {}
80 Type jvmType = new LocalClass<String>() {}.getClass().getGenericSuperclass();
81 Type ourType = Types.newParameterizedType(LocalClass.class, String.class);
82 assertEquals(jvmType, ourType);
83 }
84
85 public void testNewParameterizedType_staticLocalClass() {
86 doTestNewParameterizedType_staticLocalClass();
87 }
88
89 private static void doTestNewParameterizedType_staticLocalClass() {
90 class LocalClass<T> {}
91 Type jvmType = new LocalClass<String>() {}.getClass().getGenericSuperclass();
92 Type ourType = Types.newParameterizedType(LocalClass.class, String.class);
93 assertEquals(jvmType, ourType);
94 }
95
96 public void testNewParameterizedTypeWithOwner() {
97 ParameterizedType jvmType = (ParameterizedType)
98 new TypeCapture<Map.Entry<String, int[][]>>() {}.capture();
99 ParameterizedType ourType = Types.newParameterizedTypeWithOwner(
100 Map.class, Map.Entry.class, String.class, int[][].class);
101
102 new EqualsTester()
103 .addEqualityGroup(jvmType, ourType)
104 .addEqualityGroup(new TypeCapture<Map.Entry<String, String>>() {}.capture())
105 .addEqualityGroup(new TypeCapture<Map<String, Integer>>() {}.capture())
106 .testEquals();
107 assertEquals(jvmType.toString(), ourType.toString());
108 assertEquals(Map.class, ourType.getOwnerType());
109 assertEquals(Map.Entry.class, ourType.getRawType());
110 assertThat(ourType.getActualTypeArguments()).asList()
111 .has().exactlyAs(asList(jvmType.getActualTypeArguments())).inOrder();
112 }
113
114 public void testNewParameterizedType_serializable() {
115 SerializableTester.reserializeAndAssert(Types.newParameterizedType(
116 Map.Entry.class, String.class, Integer.class));
117 }
118
119 public void testNewParameterizedType_ownerMismatch() {
120 try {
121 Types.newParameterizedTypeWithOwner(
122 Number.class, List.class, String.class);
123 fail();
124 } catch (IllegalArgumentException expected) {}
125 }
126
127 public void testNewParameterizedType_ownerMissing() {
128 assertEquals(
129 Types.newParameterizedType(Map.Entry.class, String.class, Integer.class),
130 Types.newParameterizedTypeWithOwner(
131 null, Map.Entry.class, String.class, Integer.class));
132 }
133
134 public void testNewParameterizedType_invalidTypeParameters() {
135 try {
136 Types.newParameterizedTypeWithOwner(
137 Map.class, Map.Entry.class, String.class);
138 fail();
139 } catch (IllegalArgumentException expected) {}
140 }
141
142 public void testNewParameterizedType_primitiveTypeParameters() {
143 try {
144 Types.newParameterizedTypeWithOwner(
145 Map.class, Map.Entry.class, int.class, int.class);
146 fail();
147 } catch (IllegalArgumentException expected) {}
148 }
149
150 public void testNewArrayType() {
151 Type jvmType1 = new TypeCapture<List<String>[]>() {}.capture();
152 GenericArrayType ourType1 = (GenericArrayType) Types.newArrayType(
153 Types.newParameterizedType(List.class, String.class));
154 Type jvmType2 = new TypeCapture<List[]>() {}.capture();
155 Type ourType2 = Types.newArrayType(List.class);
156 new EqualsTester()
157 .addEqualityGroup(jvmType1, ourType1)
158 .addEqualityGroup(jvmType2, ourType2)
159 .testEquals();
160 assertEquals(new TypeCapture<List<String>>() {}.capture(),
161 ourType1.getGenericComponentType());
162 assertEquals(jvmType1.toString(), ourType1.toString());
163 assertEquals(jvmType2.toString(), ourType2.toString());
164 }
165
166 public void testNewArrayTypeOfArray() {
167 Type jvmType = new TypeCapture<int[][]>() {}.capture();
168 Type ourType = Types.newArrayType(int[].class);
169 assertEquals(jvmType.toString(), ourType.toString());
170 new EqualsTester()
171 .addEqualityGroup(jvmType, ourType)
172 .testEquals();
173 }
174
175 public void testNewArrayType_primitive() {
176 Type jvmType = new TypeCapture<int[]>() {}.capture();
177 Type ourType = Types.newArrayType(int.class);
178 assertEquals(jvmType.toString(), ourType.toString());
179 new EqualsTester()
180 .addEqualityGroup(jvmType, ourType)
181 .testEquals();
182 }
183
184 public void testNewArrayType_upperBoundedWildcard() {
185 Type wildcard = Types.subtypeOf(Number.class);
186 assertEquals(Types.subtypeOf(Number[].class), Types.newArrayType(wildcard));
187 }
188
189 public void testNewArrayType_lowerBoundedWildcard() {
190 Type wildcard = Types.supertypeOf(Number.class);
191 assertEquals(Types.supertypeOf(Number[].class), Types.newArrayType(wildcard));
192 }
193
194 public void testNewArrayType_serializable() {
195 SerializableTester.reserializeAndAssert(
196 Types.newArrayType(int[].class));
197 }
198
199 private static class WithWildcardType {
200
201 @SuppressWarnings("unused")
202 void withoutBound(List<?> list) {}
203
204 @SuppressWarnings("unused")
205 void withObjectBound(List<? extends Object> list) {}
206
207 @SuppressWarnings("unused")
208 void withUpperBound(List<? extends int[][]> list) {}
209
210 @SuppressWarnings("unused")
211 void withLowerBound(List<? super String[][]> list) {}
212
213 static WildcardType getWildcardType(String methodName) throws Exception {
214 ParameterizedType parameterType = (ParameterizedType)
215 WithWildcardType.class
216 .getDeclaredMethod(methodName, List.class)
217 .getGenericParameterTypes()[0];
218 return (WildcardType) parameterType.getActualTypeArguments()[0];
219 }
220 }
221
222 public void testNewWildcardType() throws Exception {
223 WildcardType noBoundJvmType =
224 WithWildcardType.getWildcardType("withoutBound");
225 WildcardType objectBoundJvmType =
226 WithWildcardType.getWildcardType("withObjectBound");
227 WildcardType upperBoundJvmType =
228 WithWildcardType.getWildcardType("withUpperBound");
229 WildcardType lowerBoundJvmType =
230 WithWildcardType.getWildcardType("withLowerBound");
231 WildcardType objectBound =
232 Types.subtypeOf(Object.class);
233 WildcardType upperBound =
234 Types.subtypeOf(int[][].class);
235 WildcardType lowerBound =
236 Types.supertypeOf(String[][].class);
237
238 assertEqualWildcardType(noBoundJvmType, objectBound);
239 assertEqualWildcardType(objectBoundJvmType, objectBound);
240 assertEqualWildcardType(upperBoundJvmType, upperBound);
241 assertEqualWildcardType(lowerBoundJvmType, lowerBound);
242
243 new EqualsTester()
244 .addEqualityGroup(
245 noBoundJvmType, objectBoundJvmType, objectBound)
246 .addEqualityGroup(upperBoundJvmType, upperBound)
247 .addEqualityGroup(lowerBoundJvmType, lowerBound)
248 .testEquals();
249 }
250
251 public void testNewWildcardType_primitiveTypeBound() {
252 try {
253 Types.subtypeOf(int.class);
254 fail();
255 } catch (IllegalArgumentException expected) {}
256 }
257
258 public void testNewWildcardType_serializable() {
259 SerializableTester.reserializeAndAssert(
260 Types.supertypeOf(String.class));
261 SerializableTester.reserializeAndAssert(
262 Types.subtypeOf(String.class));
263 SerializableTester.reserializeAndAssert(
264 Types.subtypeOf(Object.class));
265 }
266
267 private static void assertEqualWildcardType(
268 WildcardType expected, WildcardType actual) {
269 assertEquals(expected.toString(), actual.toString());
270 assertEquals(actual.toString(), expected.hashCode(), actual.hashCode());
271 assertThat(actual.getLowerBounds()).asList()
272 .has().exactlyAs(asList(expected.getLowerBounds())).inOrder();
273 assertThat(actual.getUpperBounds()).asList()
274 .has().exactlyAs(asList(expected.getUpperBounds())).inOrder();
275 }
276
277 private static class WithTypeVariable {
278
279 @SuppressWarnings("unused")
280 <T> void withoutBound(List<T> list) {}
281
282 @SuppressWarnings("unused")
283 <T extends Object> void withObjectBound(List<T> list) {}
284
285 @SuppressWarnings("unused")
286 <T extends Number & CharSequence> void withUpperBound(List<T> list) {}
287
288 static TypeVariable<?> getTypeVariable(String methodName) throws Exception {
289 ParameterizedType parameterType = (ParameterizedType)
290 WithTypeVariable.class
291 .getDeclaredMethod(methodName, List.class)
292 .getGenericParameterTypes()[0];
293 return (TypeVariable<?>) parameterType.getActualTypeArguments()[0];
294 }
295 }
296
297 public void testNewTypeVariable() throws Exception {
298 TypeVariable<?> noBoundJvmType =
299 WithTypeVariable.getTypeVariable("withoutBound");
300 TypeVariable<?> objectBoundJvmType =
301 WithTypeVariable.getTypeVariable("withObjectBound");
302 TypeVariable<?> upperBoundJvmType =
303 WithTypeVariable.getTypeVariable("withUpperBound");
304 TypeVariable<?> noBound = withBounds(noBoundJvmType);
305 TypeVariable<?> objectBound = withBounds(objectBoundJvmType, Object.class);
306 TypeVariable<?> upperBound = withBounds(
307 upperBoundJvmType, Number.class, CharSequence.class);
308
309 assertEqualTypeVariable(noBoundJvmType, noBound);
310 assertEqualTypeVariable(noBoundJvmType,
311 withBounds(noBoundJvmType, Object.class));
312 assertEqualTypeVariable(objectBoundJvmType, objectBound);
313 assertEqualTypeVariable(upperBoundJvmType, upperBound);
314
315 new TypeVariableEqualsTester()
316 .addEqualityGroup(noBoundJvmType, noBound)
317 .addEqualityGroup(objectBoundJvmType, objectBound)
318 .addEqualityGroup(upperBoundJvmType, upperBound)
319 .testEquals();
320 }
321
322 public void testNewTypeVariable_primitiveTypeBound() {
323 try {
324 Types.newArtificialTypeVariable(List.class, "E", int.class);
325 fail();
326 } catch (IllegalArgumentException expected) {}
327 }
328
329 public void testNewTypeVariable_serializable() throws Exception {
330 try {
331 SerializableTester.reserialize(Types.newArtificialTypeVariable(List.class, "E"));
332 fail();
333 } catch (RuntimeException expected) {}
334 }
335
336 private static <D extends GenericDeclaration> TypeVariable<D> withBounds(
337 TypeVariable<D> typeVariable, Type... bounds) {
338 return Types.newArtificialTypeVariable(
339 typeVariable.getGenericDeclaration(), typeVariable.getName(), bounds);
340 }
341
342 private static class TypeVariableEqualsTester {
343 private final EqualsTester tester = new EqualsTester();
344
345 TypeVariableEqualsTester addEqualityGroup(Type jvmType, Type... types) {
346 if (Types.NativeTypeVariableEquals.NATIVE_TYPE_VARIABLE_ONLY) {
347 tester.addEqualityGroup(jvmType);
348 tester.addEqualityGroup((Object[]) types);
349 } else {
350 tester.addEqualityGroup(Lists.asList(jvmType, types).toArray());
351 }
352 return this;
353 }
354
355 void testEquals() {
356 tester.testEquals();
357 }
358 }
359
360 private static void assertEqualTypeVariable(
361 TypeVariable<?> expected, TypeVariable<?> actual) {
362 assertEquals(expected.toString(), actual.toString());
363 assertEquals(expected.getName(), actual.getName());
364 assertEquals(
365 expected.getGenericDeclaration(), actual.getGenericDeclaration());
366 if (!Types.NativeTypeVariableEquals.NATIVE_TYPE_VARIABLE_ONLY) {
367 assertEquals(actual.toString(), expected.hashCode(), actual.hashCode());
368 }
369 assertThat(actual.getBounds()).asList()
370 .has().exactlyAs(asList(expected.getBounds())).inOrder();
371 }
372
373
374
375
376
377 public void testNewParameterizedTypeImmutability() {
378 Type[] typesIn = { String.class, Integer.class };
379 ParameterizedType parameterizedType
380 = Types.newParameterizedType(Map.class, typesIn);
381 typesIn[0] = null;
382 typesIn[1] = null;
383
384 Type[] typesOut = parameterizedType.getActualTypeArguments();
385 typesOut[0] = null;
386 typesOut[1] = null;
387
388 assertEquals(String.class, parameterizedType.getActualTypeArguments()[0]);
389 assertEquals(Integer.class, parameterizedType.getActualTypeArguments()[1]);
390 }
391
392 public void testNewParameterizedTypeWithWrongNumberOfTypeArguments() {
393 try {
394 Types.newParameterizedType(
395 Map.class, String.class, Integer.class, Long.class);
396 fail();
397 } catch (IllegalArgumentException expected) {}
398 }
399
400 public void testToString() {
401 assertEquals(int[].class.getName(), Types.toString(int[].class));
402 assertEquals(int[][].class.getName(), Types.toString(int[][].class));
403 assertEquals(String[].class.getName(), Types.toString(String[].class));
404 Type elementType = List.class.getTypeParameters()[0];
405 assertEquals(elementType.toString(), Types.toString(elementType));
406 }
407
408 public void testNullPointers() {
409 new NullPointerTester().testStaticMethods(Types.class, Visibility.PACKAGE);
410 }
411 }