View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.lang3.reflect;
18  
19  import static org.apache.commons.lang3.LangAssertions.assertIllegalArgumentException;
20  import static org.apache.commons.lang3.LangAssertions.assertNullPointerException;
21  import static org.junit.jupiter.api.Assertions.assertArrayEquals;
22  import static org.junit.jupiter.api.Assertions.assertEquals;
23  import static org.junit.jupiter.api.Assertions.assertFalse;
24  import static org.junit.jupiter.api.Assertions.assertNotEquals;
25  import static org.junit.jupiter.api.Assertions.assertNotNull;
26  import static org.junit.jupiter.api.Assertions.assertNull;
27  import static org.junit.jupiter.api.Assertions.assertTrue;
28  
29  import java.awt.Insets;
30  import java.io.Serializable;
31  import java.lang.reflect.Constructor;
32  import java.lang.reflect.Field;
33  import java.lang.reflect.GenericArrayType;
34  import java.lang.reflect.Method;
35  import java.lang.reflect.ParameterizedType;
36  import java.lang.reflect.Type;
37  import java.lang.reflect.TypeVariable;
38  import java.lang.reflect.WildcardType;
39  import java.net.URI;
40  import java.util.ArrayList;
41  import java.util.Arrays;
42  import java.util.Collection;
43  import java.util.Collections;
44  import java.util.Comparator;
45  import java.util.HashMap;
46  import java.util.List;
47  import java.util.Map;
48  import java.util.Properties;
49  import java.util.TreeSet;
50  import java.util.stream.Stream;
51  
52  import org.apache.commons.lang3.AbstractLangTest;
53  import org.apache.commons.lang3.reflect.testbed.Foo;
54  import org.apache.commons.lang3.reflect.testbed.GenericParent;
55  import org.apache.commons.lang3.reflect.testbed.GenericTypeHolder;
56  import org.apache.commons.lang3.reflect.testbed.StringParameterizedChild;
57  import org.junit.jupiter.api.Disabled;
58  import org.junit.jupiter.api.Test;
59  import org.junit.jupiter.params.ParameterizedTest;
60  import org.junit.jupiter.params.provider.MethodSource;
61  
62  /**
63   * Test fixture for https://issues.apache.org/jira/browse/LANG-1524
64   *
65   * @param <T> Test fixture type, unused type parameter for test.
66   */
67  class AAAAClass<T extends AAAAClass.BBBBClass.CCCClass> {
68      public static class BBBBClass {
69          public static class CCCClass {
70              // empty
71          }
72      }
73  }
74  
75  final class AAAClass extends AAClass<String> {
76      public class BBBClass extends BBClass<String> {
77          // empty
78      }
79  }
80  
81  /**
82   * Test fixture.
83   *
84   * @param <T> Test fixture type, unused type parameter for test.
85   */
86  class AAClass<T> {
87  
88      /**
89       * Test fixture.
90       *
91       * @param <S> Test fixture type, unused type parameter for test.
92       */
93      public class BBClass<S> {
94          // empty
95      }
96  }
97  
98  @SuppressWarnings("rawtypes")
99  //raw types, where used, are used purposely
100 final class AClass extends AAClass<String>.BBClass<Number> {
101 
102     @SuppressWarnings("unused") // Unused type parameter for test
103     public interface AInterface<T> {
104         // empty
105     }
106 
107     @SuppressWarnings("unused") // Unused type parameter for test
108     public class BClass<T> {
109         // empty
110     }
111 
112     @SuppressWarnings("unused") // Unused type parameter for test
113     public class CClass<T> extends BClass {
114         // empty
115     }
116 
117     @SuppressWarnings("unused") // Unused type parameter for test
118     public class DClass<T> extends CClass<T> {
119         // empty
120     }
121 
122     @SuppressWarnings("unused") // Unused type parameter for test
123     public class EClass<T> extends DClass {
124         // empty
125     }
126 
127     public class FClass extends EClass<String> {
128         // empty
129     }
130 
131     public class GClass<T extends BClass<? extends T> & AInterface<AInterface<? super T>>> {
132         // empty
133     }
134 
135     public BClass<Number> bClass;
136 
137     public CClass<? extends String> cClass;
138 
139     public DClass<String> dClass;
140 
141     public EClass<String> eClass;
142 
143     public FClass fClass;
144 
145     public GClass gClass;
146 
147     AClass(final AAClass<String> enclosingInstance) {
148         enclosingInstance.super();
149     }
150 }
151 @SuppressWarnings("rawtypes")
152 abstract class Test1<G> {
153     public abstract Object m0();
154     public abstract String[] m1();
155     public abstract <K, V> Map<? extends K, V[]> m10();
156     public abstract <K, V> Map<? extends K, List<V[]>> m11();
157     public abstract List m12();
158     public abstract Map m13();
159     public abstract Properties m14();
160     public abstract G m15();
161     public abstract List<G> m16();
162     public abstract Enum m17();
163     public abstract <E> E[] m2();
164     public abstract <E> List<? extends E> m3();
165     public abstract <E extends Enum<E>> List<? extends Enum<E>> m4();
166     public abstract List<? extends Enum<?>> m5();
167     public abstract List<? super Enum<?>> m6();
168     public abstract List<?> m7();
169     public abstract Map<? extends Enum<?>, ? super Enum<?>> m8();
170     public abstract <K, V> Map<? extends K, ? super V[]> m9();
171 }
172 
173 /**
174  * Tests {@link TypeUtils}.
175  *
176  * @param <B> Type for test fixtures.
177  */
178 @SuppressWarnings({ "unused", "rawtypes" })
179 // raw types, where used, are used purposely
180 public class TypeUtilsTest<B> extends AbstractLangTest {
181 
182     public interface And<K, V> extends This<Number, Number> {
183         // empty
184     }
185 
186     public static class ClassWithSuperClassWithGenericType extends ArrayList<Object> {
187         private static final long serialVersionUID = 1L;
188 
189         public static <U> Iterable<U> methodWithGenericReturnType() {
190             return null;
191         }
192     }
193 
194     /** This non-static inner class is parameterized. */
195     private class MyInnerClass<T> {
196 
197         class MyInnerClass2<X> {
198             // empty
199         }
200     }
201 
202     public class Other<T> implements This<String, T> {
203         // empty
204     }
205 
206     public class Tester implements This<String, B> {
207         // empty
208     }
209 
210     public class That<K, V> implements This<K, V> {
211         // empty
212     }
213 
214     public class The<K, V> extends That<Number, Number> implements And<String, String> {
215         // empty
216     }
217 
218     public class Thing<Q> extends Other<B> {
219         // empty
220     }
221 
222     public interface This<K, V> {
223         // empty
224     }
225 
226     public static Comparable<Integer> intComparable;
227 
228     public static Comparable<Long> longComparable;
229 
230     public static Comparable<String> stringComparable;
231 
232     public static List<String>[] stringListArray;
233 
234     public static URI uri;
235 
236     public static Comparable<URI> uriComparable;
237 
238     public static Comparable<?> wildcardComparable;
239 
240     public static <G extends Comparable<G>> G stub() {
241         return null;
242     }
243 
244     public static <G extends Comparable<? super G>> G stub2() {
245         return null;
246     }
247 
248     public static <T extends Comparable<? extends T>> T stub3() {
249         return null;
250     }
251 
252     static Stream<Type> testTypeToString() {
253         // @formatter:off
254         return Stream.of(Comparator.class, Comparable.class, ArrayList.class, HashMap.class)
255                 .flatMap(cls -> Stream.of(cls.getDeclaredMethods()))
256                 .flatMap(m ->
257                     Stream.concat(Stream.of(m.getGenericExceptionTypes()),
258                     Stream.concat(Stream.of(m.getGenericParameterTypes()),
259                     Stream.concat(Stream.of(m.getGenericReturnType()), Stream.of(m.getTypeParameters())))));
260         // @formatter:on
261     }
262 
263     public The<String, String> da;
264 
265     public That<String, String> dat;
266 
267     public TypeUtilsTest<String>.That<String, String> dat2;
268 
269     public TypeUtilsTest<Number>.That<String, String> dat3;
270 
271     public Thing ding;
272 
273     public This<String, String> dis;
274 
275     public Comparable<? extends Integer>[] intWildcardComparable;
276 
277     public Iterable<? extends Map<Integer, ? extends Collection<?>>> iterable;
278 
279     public TypeUtilsTest<String>.Tester tester;
280 
281     public Tester tester2;
282 
283     public Other<String> uhder;
284 
285     /** The inner class is used as a return type from a method. */
286     private <U> MyInnerClass<U> aMethod() {
287         return null;
288     }
289 
290     @Test
291     void test_LANG_1114() throws NoSuchFieldException {
292         final Type nonWildcardType = getClass().getDeclaredField("wildcardComparable").getGenericType();
293         final Type wildcardType = ((ParameterizedType) nonWildcardType).getActualTypeArguments()[0];
294 
295         assertFalse(TypeUtils.equals(wildcardType, nonWildcardType));
296         assertFalse(TypeUtils.equals(nonWildcardType, wildcardType));
297     }
298 
299     @Test
300     void test_LANG_1190() throws NoSuchMethodException {
301         final Type fromType = ClassWithSuperClassWithGenericType.class.getDeclaredMethod("methodWithGenericReturnType").getGenericReturnType();
302         final Type failingToType = TypeUtils.wildcardType().withLowerBounds(ClassWithSuperClassWithGenericType.class).build();
303 
304         assertTrue(TypeUtils.isAssignable(fromType, failingToType));
305     }
306 
307     @Test
308     void test_LANG_1348() throws NoSuchMethodException {
309         final Method method = Enum.class.getMethod("valueOf", Class.class, String.class);
310         assertEquals("T extends java.lang.Enum<T>", TypeUtils.toString(method.getGenericReturnType()));
311     }
312 
313     @Test
314     void test_LANG_1524() {
315         assertEquals("AAAAClass(cycle).BBBBClass.CCCClass", TypeUtils.toString(AAAAClass.BBBBClass.CCCClass.class));
316         assertEquals("AAAAClass(cycle).BBBBClass", TypeUtils.toString(AAAAClass.BBBBClass.class));
317         assertEquals("AAAAClass(cycle)", TypeUtils.toString(AAAAClass.class));
318     }
319 
320     /**
321      * Tests https://issues.apache.org/jira/projects/LANG/issues/LANG-1698
322      *
323      * <pre>{@code
324      * java.lang.StackOverflowError
325     at org.apache.commons.lang3.reflect.TypeUtils.typeVariableToString(TypeUtils.java:1785)
326     at org.apache.commons.lang3.reflect.TypeUtils.toString(TypeUtils.java:1737)
327     at org.apache.commons.lang3.reflect.TypeUtils.toString(TypeUtils.java:1714)
328     at org.apache.commons.lang3.reflect.TypeUtils.appendAllTo(TypeUtils.java:302)
329     at org.apache.commons.lang3.reflect.TypeUtils.wildcardTypeToString(TypeUtils.java:1902)
330     at org.apache.commons.lang3.reflect.TypeUtils.toString(TypeUtils.java:1734)
331     at org.apache.commons.lang3.reflect.TypeUtils.toString(TypeUtils.java:1714)
332     at org.apache.commons.lang3.reflect.TypeUtils.appendAllTo(TypeUtils.java:302)
333     at org.apache.commons.lang3.reflect.TypeUtils.parameterizedTypeToString(TypeUtils.java:1604)
334     at org.apache.commons.lang3.reflect.TypeUtils.toString(TypeUtils.java:1731)
335     at org.apache.commons.lang3.reflect.TypeUtils.toString(TypeUtils.java:1714)
336     at org.apache.commons.lang3.reflect.TypeUtils.appendAllTo(TypeUtils.java:302)
337     at org.apache.commons.lang3.reflect.TypeUtils.typeVariableToString(TypeUtils.java:1789)
338      * }
339      * </pre>
340      */
341     @Test
342     void test_LANG_1698() {
343         final ParameterizedType comparing = (ParameterizedType) Arrays.stream(Comparator.class.getDeclaredMethods())
344                 .filter(k -> k.getName().equals("comparing")).findFirst()
345                 .orElse(Comparator.class.getDeclaredMethods()[0]).getGenericParameterTypes()[0];
346         final String typeName = TypeUtils
347                 .parameterize((Class<?>) comparing.getRawType(), comparing.getActualTypeArguments()).getTypeName();
348         assertEquals("java.util.function.Function<? super T, ? extends U>", typeName);
349     }
350 
351     @Test
352     void test_LANG_1702() throws NoSuchMethodException, SecurityException {
353         final Type type = TypeUtilsTest.class.getDeclaredMethod("aMethod").getGenericReturnType();
354 
355         // any map will do
356         final Map<TypeVariable<?>, Type> typeArguments = Collections.emptyMap();
357 
358         // this fails with a stack overflow
359         final Type unrolledType = TypeUtils.unrollVariables(typeArguments, type);
360     }
361 
362     @Test
363     void testContainsTypeVariables() throws NoSuchMethodException {
364         assertFalse(TypeUtils.containsTypeVariables(Test1.class.getMethod("m0").getGenericReturnType()));
365         assertFalse(TypeUtils.containsTypeVariables(Test1.class.getMethod("m1").getGenericReturnType()));
366         assertTrue(TypeUtils.containsTypeVariables(Test1.class.getMethod("m2").getGenericReturnType()));
367         assertTrue(TypeUtils.containsTypeVariables(Test1.class.getMethod("m3").getGenericReturnType()));
368         assertTrue(TypeUtils.containsTypeVariables(Test1.class.getMethod("m4").getGenericReturnType()));
369         assertFalse(TypeUtils.containsTypeVariables(Test1.class.getMethod("m5").getGenericReturnType()));
370         assertFalse(TypeUtils.containsTypeVariables(Test1.class.getMethod("m6").getGenericReturnType()));
371         assertFalse(TypeUtils.containsTypeVariables(Test1.class.getMethod("m7").getGenericReturnType()));
372         assertFalse(TypeUtils.containsTypeVariables(Test1.class.getMethod("m8").getGenericReturnType()));
373         assertTrue(TypeUtils.containsTypeVariables(Test1.class.getMethod("m9").getGenericReturnType()));
374         assertTrue(TypeUtils.containsTypeVariables(Test1.class.getMethod("m10").getGenericReturnType()));
375         assertTrue(TypeUtils.containsTypeVariables(Test1.class.getMethod("m11").getGenericReturnType()));
376         assertTrue(TypeUtils.containsTypeVariables(Test1.class.getMethod("m12").getGenericReturnType()));
377         assertTrue(TypeUtils.containsTypeVariables(Test1.class.getMethod("m13").getGenericReturnType()));
378         assertFalse(TypeUtils.containsTypeVariables(Test1.class.getMethod("m14").getGenericReturnType()));
379         assertTrue(TypeUtils.containsTypeVariables(Test1.class.getMethod("m15").getGenericReturnType()));
380         assertTrue(TypeUtils.containsTypeVariables(Test1.class.getMethod("m16").getGenericReturnType()));
381         assertTrue(TypeUtils.containsTypeVariables(Test1.class.getMethod("m17").getGenericReturnType()));
382     }
383 
384     @Test
385     void testContainsTypeVariablesPr437() throws Exception {
386         abstract class Test2<G> {
387             public abstract Object m0();
388             public abstract String[] m1();
389             public abstract <K, V> Map<? extends K, V[]> m10();
390             public abstract <K, V> Map<? extends K, List<V[]>> m11();
391             public abstract List m12();
392             public abstract Map m13();
393             public abstract Properties m14();
394             public abstract G m15();
395             public abstract List<G> m16();
396             public abstract Enum m17();
397             public abstract <E> E[] m2();
398             public abstract <E> List<? extends E> m3();
399             public abstract <E extends Enum<E>> List<? extends Enum<E>> m4();
400             public abstract List<? extends Enum<?>> m5();
401             public abstract List<? super Enum<?>> m6();
402             public abstract List<?> m7();
403             public abstract Map<? extends Enum<?>, ? super Enum<?>> m8();
404             public abstract <K, V> Map<? extends K, ? super V[]> m9();
405         }
406 
407         assertFalse(TypeUtils.containsTypeVariables(Test2.class.getMethod("m0").getGenericReturnType()));
408         assertFalse(TypeUtils.containsTypeVariables(Test2.class.getMethod("m1").getGenericReturnType()));
409         assertTrue(TypeUtils.containsTypeVariables(Test2.class.getMethod("m2").getGenericReturnType()));
410         assertTrue(TypeUtils.containsTypeVariables(Test2.class.getMethod("m3").getGenericReturnType()));
411         assertTrue(TypeUtils.containsTypeVariables(Test2.class.getMethod("m4").getGenericReturnType()));
412         assertFalse(TypeUtils.containsTypeVariables(Test2.class.getMethod("m5").getGenericReturnType()));
413         assertFalse(TypeUtils.containsTypeVariables(Test2.class.getMethod("m6").getGenericReturnType()));
414         assertFalse(TypeUtils.containsTypeVariables(Test2.class.getMethod("m7").getGenericReturnType()));
415         assertFalse(TypeUtils.containsTypeVariables(Test2.class.getMethod("m8").getGenericReturnType()));
416         assertTrue(TypeUtils.containsTypeVariables(Test2.class.getMethod("m9").getGenericReturnType()));
417         assertTrue(TypeUtils.containsTypeVariables(Test2.class.getMethod("m10").getGenericReturnType()));
418         assertTrue(TypeUtils.containsTypeVariables(Test2.class.getMethod("m11").getGenericReturnType()));
419         assertTrue(TypeUtils.containsTypeVariables(Test2.class.getMethod("m12").getGenericReturnType()));
420         assertTrue(TypeUtils.containsTypeVariables(Test2.class.getMethod("m13").getGenericReturnType()));
421         assertFalse(TypeUtils.containsTypeVariables(Test2.class.getMethod("m14").getGenericReturnType()));
422         assertTrue(TypeUtils.containsTypeVariables(Test2.class.getMethod("m15").getGenericReturnType()));
423         assertTrue(TypeUtils.containsTypeVariables(Test2.class.getMethod("m16").getGenericReturnType()));
424         assertTrue(TypeUtils.containsTypeVariables(Test2.class.getMethod("m17").getGenericReturnType()));
425     }
426 
427     @Test
428     void testDeprecatedConstructor() {
429         assertNotNull(new TypeUtils().toString());
430     }
431 
432     @Test
433     void testDetermineTypeArguments() throws NoSuchFieldException {
434         final ParameterizedType iterableType = (ParameterizedType) getClass().getField("iterable").getGenericType();
435         assertNull(TypeUtils.determineTypeArguments(Object.class, iterableType));
436         final Map<TypeVariable<?>, Type> typeVarAssigns = TypeUtils.determineTypeArguments(TreeSet.class, iterableType);
437         final TypeVariable<?> treeSetTypeVar = TreeSet.class.getTypeParameters()[0];
438         assertTrue(typeVarAssigns.containsKey(treeSetTypeVar));
439         assertEquals(iterableType.getActualTypeArguments()[0], typeVarAssigns.get(treeSetTypeVar));
440         assertNullPointerException(() -> TypeUtils.determineTypeArguments(TreeSet.class, null));
441         assertNullPointerException(() -> TypeUtils.determineTypeArguments(null, iterableType));
442     }
443 
444     @Test
445     void testEquals() throws NoSuchFieldException {
446         final Type expected = getClass().getField("intWildcardComparable").getGenericType();
447         final GenericArrayType gat1 = TypeUtils
448                 .genericArrayType(TypeUtils.parameterize(Comparable.class, TypeUtils.wildcardType().withUpperBounds(Integer.class).build()));
449         final GenericArrayType gat2 = TypeUtils
450                 .genericArrayType(TypeUtils.parameterize(Comparable.class, TypeUtils.wildcardType().withUpperBounds(Integer.class).build()));
451         assertTrue(TypeUtils.equals(gat1, gat1));
452         assertTrue(TypeUtils.equals(gat1, gat2));
453         assertFalse(TypeUtils.equals(gat1, null));
454         assertFalse(TypeUtils.equals(null, gat1));
455     }
456 
457     @SuppressWarnings("unlikely-arg-type")
458     @Test
459     void testGenericArrayType() throws NoSuchFieldException {
460         final Type expected = getClass().getField("intWildcardComparable").getGenericType();
461         final GenericArrayType actual = TypeUtils
462                 .genericArrayType(TypeUtils.parameterize(Comparable.class, TypeUtils.wildcardType().withUpperBounds(Integer.class).build()));
463         assertTrue(TypeUtils.equals(expected, actual));
464         assertEquals("java.lang.Comparable<? extends java.lang.Integer>[]", actual.toString());
465         assertNotEquals(0, actual.hashCode());
466         assertEquals(actual, actual);
467         assertFalse(actual.equals(null));
468         assertFalse(actual.equals(TypeUtils.wildcardType().build()));
469     }
470 
471     @Test
472     void testGetArrayComponentType() throws NoSuchFieldException {
473         final Type rawListType = GenericTypeHolder.class.getDeclaredField("rawList").getGenericType();
474         final Type objectListType = GenericTypeHolder.class.getDeclaredField("objectList").getGenericType();
475         final Type unboundListType = GenericTypeHolder.class.getDeclaredField("unboundList").getGenericType();
476         final Type superObjectListType = GenericTypeHolder.class.getDeclaredField("superObjectList").getGenericType();
477         final Type stringListType = GenericTypeHolder.class.getDeclaredField("stringList").getGenericType();
478         final Type subStringListType = GenericTypeHolder.class.getDeclaredField("subStringList").getGenericType();
479         final Type superStringListType = GenericTypeHolder.class.getDeclaredField("superStringList").getGenericType();
480 
481         assertNull(TypeUtils.getArrayComponentType(rawListType));
482         assertNull(TypeUtils.getArrayComponentType(objectListType));
483         assertNull(TypeUtils.getArrayComponentType(unboundListType));
484         assertNull(TypeUtils.getArrayComponentType(superObjectListType));
485         assertNull(TypeUtils.getArrayComponentType(stringListType));
486         assertNull(TypeUtils.getArrayComponentType(subStringListType));
487         assertNull(TypeUtils.getArrayComponentType(superStringListType));
488 
489         final Type rawListTypeArray = GenericTypeHolder.class.getDeclaredField("rawListArray").getGenericType();
490         final Type objectListTypeArray = GenericTypeHolder.class.getDeclaredField("objectListArray").getGenericType();
491         final Type unboundListTypeArray = GenericTypeHolder.class.getDeclaredField("unboundListArray").getGenericType();
492         final Type superObjectListTypeArray = GenericTypeHolder.class.getDeclaredField("superObjectListArray").getGenericType();
493         final Type stringListTypeArray = GenericTypeHolder.class.getDeclaredField("stringListArray").getGenericType();
494         final Type subStringListTypeArray = GenericTypeHolder.class.getDeclaredField("subStringListArray").getGenericType();
495         final Type superStringListTypeArray = GenericTypeHolder.class.getDeclaredField("superStringListArray").getGenericType();
496 
497         assertEquals(rawListType, TypeUtils.getArrayComponentType(rawListTypeArray));
498         assertEquals(objectListType, TypeUtils.getArrayComponentType(objectListTypeArray));
499         assertEquals(unboundListType, TypeUtils.getArrayComponentType(unboundListTypeArray));
500         assertEquals(superObjectListType, TypeUtils.getArrayComponentType(superObjectListTypeArray));
501         assertEquals(stringListType, TypeUtils.getArrayComponentType(stringListTypeArray));
502         assertEquals(subStringListType, TypeUtils.getArrayComponentType(subStringListTypeArray));
503         assertEquals(superStringListType, TypeUtils.getArrayComponentType(superStringListTypeArray));
504     }
505 
506     @Test
507     void testGetPrimitiveArrayComponentType() {
508         assertEquals(boolean.class, TypeUtils.getArrayComponentType(boolean[].class));
509         assertEquals(byte.class, TypeUtils.getArrayComponentType(byte[].class));
510         assertEquals(short.class, TypeUtils.getArrayComponentType(short[].class));
511         assertEquals(int.class, TypeUtils.getArrayComponentType(int[].class));
512         assertEquals(char.class, TypeUtils.getArrayComponentType(char[].class));
513         assertEquals(long.class, TypeUtils.getArrayComponentType(long[].class));
514         assertEquals(float.class, TypeUtils.getArrayComponentType(float[].class));
515         assertEquals(double.class, TypeUtils.getArrayComponentType(double[].class));
516 
517         assertNull(TypeUtils.getArrayComponentType(boolean.class));
518         assertNull(TypeUtils.getArrayComponentType(byte.class));
519         assertNull(TypeUtils.getArrayComponentType(short.class));
520         assertNull(TypeUtils.getArrayComponentType(int.class));
521         assertNull(TypeUtils.getArrayComponentType(char.class));
522         assertNull(TypeUtils.getArrayComponentType(long.class));
523         assertNull(TypeUtils.getArrayComponentType(float.class));
524         assertNull(TypeUtils.getArrayComponentType(double.class));
525     }
526 
527     @Test
528     void testGetRawType() throws NoSuchFieldException {
529         final Type stringParentFieldType = GenericTypeHolder.class.getDeclaredField("stringParent").getGenericType();
530         final Type integerParentFieldType = GenericTypeHolder.class.getDeclaredField("integerParent").getGenericType();
531         final Type foosFieldType = GenericTypeHolder.class.getDeclaredField("foos").getGenericType();
532         final Type genericParentT = GenericParent.class.getTypeParameters()[0];
533         assertEquals(GenericParent.class, TypeUtils.getRawType(stringParentFieldType, null));
534         assertEquals(GenericParent.class, TypeUtils.getRawType(integerParentFieldType, null));
535         assertEquals(List.class, TypeUtils.getRawType(foosFieldType, null));
536         assertEquals(String.class, TypeUtils.getRawType(genericParentT, StringParameterizedChild.class));
537         assertEquals(String.class, TypeUtils.getRawType(genericParentT, stringParentFieldType));
538         assertEquals(Foo.class, TypeUtils.getRawType(Iterable.class.getTypeParameters()[0], foosFieldType));
539         assertEquals(Foo.class, TypeUtils.getRawType(List.class.getTypeParameters()[0], foosFieldType));
540         assertNull(TypeUtils.getRawType(genericParentT, GenericParent.class));
541         assertEquals(GenericParent[].class, TypeUtils.getRawType(GenericTypeHolder.class.getDeclaredField("barParents").getGenericType(), null));
542     }
543 
544     /**
545      * Tests https://issues.apache.org/jira/browse/LANG-1697
546      */
547     @Test
548     void testGetRawType_LANG_1697() {
549         assertEquals(int[].class, TypeUtils.getRawType(TypeUtils.genericArrayType(Integer.TYPE), Integer.TYPE));
550         // LANG-1697:
551         assertNull(TypeUtils.getRawType(TypeUtils.genericArrayType(TypeUtils.WILDCARD_ALL), null));
552         // TODO: Is this correct?
553         assertNull(TypeUtils.getRawType(TypeUtils.genericArrayType(TypeUtils.WILDCARD_ALL), TypeUtils.WILDCARD_ALL));
554         // TODO: Is this correct?
555         assertNull(TypeUtils.getRawType(TypeUtils.genericArrayType(TypeUtils.WILDCARD_ALL), Integer.TYPE));
556     }
557 
558     @Test
559     void testGetTypeArguments() {
560         Map<TypeVariable<?>, Type> typeVarAssigns;
561         TypeVariable<?> treeSetTypeVar;
562         Type typeArg;
563 
564         typeVarAssigns = TypeUtils.getTypeArguments(Integer.class, Comparable.class);
565         treeSetTypeVar = Comparable.class.getTypeParameters()[0];
566         assertTrue(typeVarAssigns.containsKey(treeSetTypeVar),
567                 "Type var assigns for Comparable from Integer: " + typeVarAssigns);
568         typeArg = typeVarAssigns.get(treeSetTypeVar);
569         assertEquals(Integer.class, typeVarAssigns.get(treeSetTypeVar),
570                 "Type argument of Comparable from Integer: " + typeArg);
571 
572         typeVarAssigns = TypeUtils.getTypeArguments(int.class, Comparable.class);
573         treeSetTypeVar = Comparable.class.getTypeParameters()[0];
574         assertTrue(typeVarAssigns.containsKey(treeSetTypeVar),
575                 "Type var assigns for Comparable from int: " + typeVarAssigns);
576         typeArg = typeVarAssigns.get(treeSetTypeVar);
577         assertEquals(Integer.class, typeVarAssigns.get(treeSetTypeVar),
578                 "Type argument of Comparable from int: " + typeArg);
579 
580         final Collection<Integer> col = Collections.emptyList();
581         typeVarAssigns = TypeUtils.getTypeArguments(List.class, Collection.class);
582         treeSetTypeVar = Comparable.class.getTypeParameters()[0];
583         assertFalse(typeVarAssigns.containsKey(treeSetTypeVar),
584                 "Type var assigns for Collection from List: " + typeVarAssigns);
585 
586         typeVarAssigns = TypeUtils.getTypeArguments(AAAClass.BBBClass.class, AAClass.BBClass.class);
587         assertEquals(2, typeVarAssigns.size());
588         assertEquals(String.class, typeVarAssigns.get(AAClass.class.getTypeParameters()[0]));
589         assertEquals(String.class, typeVarAssigns.get(AAClass.BBClass.class.getTypeParameters()[0]));
590 
591         typeVarAssigns = TypeUtils.getTypeArguments(Other.class, This.class);
592         assertEquals(2, typeVarAssigns.size());
593         assertEquals(String.class, typeVarAssigns.get(This.class.getTypeParameters()[0]));
594         assertEquals(Other.class.getTypeParameters()[0], typeVarAssigns.get(This.class.getTypeParameters()[1]));
595 
596         typeVarAssigns = TypeUtils.getTypeArguments(And.class, This.class);
597         assertEquals(2, typeVarAssigns.size());
598         assertEquals(Number.class, typeVarAssigns.get(This.class.getTypeParameters()[0]));
599         assertEquals(Number.class, typeVarAssigns.get(This.class.getTypeParameters()[1]));
600 
601         typeVarAssigns = TypeUtils.getTypeArguments(Thing.class, Other.class);
602         assertEquals(2, typeVarAssigns.size());
603         assertEquals(getClass().getTypeParameters()[0], typeVarAssigns.get(getClass().getTypeParameters()[0]));
604         assertEquals(getClass().getTypeParameters()[0], typeVarAssigns.get(Other.class.getTypeParameters()[0]));
605     }
606 
607     @Test
608     void testIsArrayGenericTypes() throws NoSuchFieldException {
609         final Type rawListType = GenericTypeHolder.class.getDeclaredField("rawList").getGenericType();
610         final Type objectListType = GenericTypeHolder.class.getDeclaredField("objectList").getGenericType();
611         final Type unboundListType = GenericTypeHolder.class.getDeclaredField("unboundList").getGenericType();
612         final Type superObjectListType = GenericTypeHolder.class.getDeclaredField("superObjectList").getGenericType();
613         final Type stringListType = GenericTypeHolder.class.getDeclaredField("stringList").getGenericType();
614         final Type subStringListType = GenericTypeHolder.class.getDeclaredField("subStringList").getGenericType();
615         final Type superStringListType = GenericTypeHolder.class.getDeclaredField("superStringList").getGenericType();
616 
617         assertFalse(TypeUtils.isArrayType(rawListType));
618         assertFalse(TypeUtils.isArrayType(objectListType));
619         assertFalse(TypeUtils.isArrayType(unboundListType));
620         assertFalse(TypeUtils.isArrayType(superObjectListType));
621         assertFalse(TypeUtils.isArrayType(stringListType));
622         assertFalse(TypeUtils.isArrayType(subStringListType));
623         assertFalse(TypeUtils.isArrayType(superStringListType));
624 
625         final Type rawListTypeArray = GenericTypeHolder.class.getDeclaredField("rawListArray").getGenericType();
626         final Type objectListTypeArray = GenericTypeHolder.class.getDeclaredField("objectListArray").getGenericType();
627         final Type unboundListTypeArray = GenericTypeHolder.class.getDeclaredField("unboundListArray").getGenericType();
628         final Type superObjectListTypeArray = GenericTypeHolder.class.getDeclaredField("superObjectListArray").getGenericType();
629         final Type stringListTypeArray = GenericTypeHolder.class.getDeclaredField("stringListArray").getGenericType();
630         final Type subStringListTypeArray = GenericTypeHolder.class.getDeclaredField("subStringListArray").getGenericType();
631         final Type superStringListTypeArray = GenericTypeHolder.class.getDeclaredField("superStringListArray").getGenericType();
632 
633         assertTrue(TypeUtils.isArrayType(rawListTypeArray));
634         assertTrue(TypeUtils.isArrayType(objectListTypeArray));
635         assertTrue(TypeUtils.isArrayType(unboundListTypeArray));
636         assertTrue(TypeUtils.isArrayType(superObjectListTypeArray));
637         assertTrue(TypeUtils.isArrayType(stringListTypeArray));
638         assertTrue(TypeUtils.isArrayType(subStringListTypeArray));
639         assertTrue(TypeUtils.isArrayType(superStringListTypeArray));
640     }
641 
642     @Test
643     void testIsArrayTypeClasses() {
644         assertTrue(TypeUtils.isArrayType(boolean[].class));
645         assertTrue(TypeUtils.isArrayType(byte[].class));
646         assertTrue(TypeUtils.isArrayType(short[].class));
647         assertTrue(TypeUtils.isArrayType(int[].class));
648         assertTrue(TypeUtils.isArrayType(char[].class));
649         assertTrue(TypeUtils.isArrayType(long[].class));
650         assertTrue(TypeUtils.isArrayType(float[].class));
651         assertTrue(TypeUtils.isArrayType(double[].class));
652         assertTrue(TypeUtils.isArrayType(Object[].class));
653         assertTrue(TypeUtils.isArrayType(String[].class));
654 
655         assertFalse(TypeUtils.isArrayType(boolean.class));
656         assertFalse(TypeUtils.isArrayType(byte.class));
657         assertFalse(TypeUtils.isArrayType(short.class));
658         assertFalse(TypeUtils.isArrayType(int.class));
659         assertFalse(TypeUtils.isArrayType(char.class));
660         assertFalse(TypeUtils.isArrayType(long.class));
661         assertFalse(TypeUtils.isArrayType(float.class));
662         assertFalse(TypeUtils.isArrayType(double.class));
663         assertFalse(TypeUtils.isArrayType(Object.class));
664         assertFalse(TypeUtils.isArrayType(String.class));
665     }
666 
667     @Test
668     void testIsAssignableClasses() {
669         assertTrue(TypeUtils.isAssignable(char.class, double.class));
670         assertTrue(TypeUtils.isAssignable(byte.class, double.class));
671         assertTrue(TypeUtils.isAssignable(short.class, double.class));
672         assertTrue(TypeUtils.isAssignable(int.class, double.class));
673         assertTrue(TypeUtils.isAssignable(long.class, double.class));
674         assertTrue(TypeUtils.isAssignable(float.class, double.class));
675 
676         assertTrue(TypeUtils.isAssignable(int.class, long.class));
677         assertTrue(TypeUtils.isAssignable(Integer.class, long.class));
678         assertFalse(TypeUtils.isAssignable(int.class, Long.class));
679         assertFalse(TypeUtils.isAssignable(Integer.class, Long.class));
680         assertTrue(TypeUtils.isAssignable(Integer.class, int.class));
681         assertTrue(TypeUtils.isAssignable(int.class, Integer.class));
682         assertTrue(TypeUtils.isAssignable(int.class, Number.class));
683         assertTrue(TypeUtils.isAssignable(int.class, Object.class));
684         assertTrue(TypeUtils.isAssignable(int.class, Comparable.class));
685         assertTrue(TypeUtils.isAssignable(int.class, Serializable.class));
686 
687         assertFalse(TypeUtils.isAssignable(int[].class, long[].class));
688         assertFalse(TypeUtils.isAssignable(Integer[].class, int[].class));
689         assertFalse(TypeUtils.isAssignable(int[].class, Object[].class));
690         assertTrue(TypeUtils.isAssignable(Integer[].class, Object[].class));
691     }
692 
693     @Test
694     void testIsAssignableDirectClassHierarchy() throws NoSuchFieldException {
695         final Type bClassType = AClass.class.getField("bClass").getGenericType(); // B is superclass
696         final Type cClassType = AClass.class.getField("cClass").getGenericType(); // C subclass of B
697         final Type dClassType = AClass.class.getField("dClass").getGenericType(); // D subclass of C
698         final Type eClassType = AClass.class.getField("eClass").getGenericType(); // E subclass of D
699         final Type fClassType = AClass.class.getField("fClass").getGenericType(); // F subclass of E
700 
701         assertTrue(TypeUtils.isAssignable(cClassType, bClassType));
702         assertTrue(TypeUtils.isAssignable(dClassType, bClassType));
703         assertTrue(TypeUtils.isAssignable(eClassType, bClassType));
704         assertTrue(TypeUtils.isAssignable(fClassType, bClassType));
705 
706         assertTrue(TypeUtils.isAssignable(dClassType, cClassType));
707         assertTrue(TypeUtils.isAssignable(eClassType, cClassType));
708         assertTrue(TypeUtils.isAssignable(fClassType, cClassType));
709 
710         assertTrue(TypeUtils.isAssignable(eClassType, dClassType));
711         assertTrue(TypeUtils.isAssignable(fClassType, dClassType));
712 
713         assertTrue(TypeUtils.isAssignable(fClassType, eClassType));
714     }
715 
716     @Test
717     void testIsAssignableGenericArrayTypeToObject() {
718         final Class<Constructor> rawClass = Constructor.class;
719         final Class<Insets> typeArgClass = Insets.class;
720         // Builds a ParameterizedType for Constructor<Insets>
721         final ParameterizedType paramType = TypeUtils.parameterize(rawClass, typeArgClass);
722         assertEquals(rawClass, paramType.getRawType());
723         assertEquals(typeArgClass, paramType.getActualTypeArguments()[0]);
724 
725         assertTrue(Object.class.isAssignableFrom(paramType.getClass()));
726         assertFalse(paramType.getClass().isAssignableFrom(Object.class));
727 
728         final Type testType = Object.class;
729         assertTrue(TypeUtils.isAssignable(paramType, testType),
730                 () -> String.format("TypeUtils.isAssignable(%s, %s)", paramType, testType));
731         assertFalse(TypeUtils.isAssignable(testType, paramType),
732                 () -> String.format("TypeUtils.isAssignable(%s, %s)", testType, paramType));
733     }
734 
735     @Test
736     void testIsAssignableGenericArrayTypeToParameterizedType() {
737         final Class<Constructor> rawClass = Constructor.class;
738         final Class<Insets> typeArgClass = Insets.class;
739         // Builds a ParameterizedType for Constructor<Insets>
740         final ParameterizedType paramType = TypeUtils.parameterize(rawClass, typeArgClass);
741         assertEquals(rawClass, paramType.getRawType());
742         assertEquals(typeArgClass, paramType.getActualTypeArguments()[0]);
743 
744         assertFalse(GenericArrayType.class.isAssignableFrom(paramType.getClass()));
745         assertFalse(paramType.getClass().isAssignableFrom(GenericArrayType.class));
746 
747         final GenericArrayType testType = TypeUtils.genericArrayType(paramType);
748         assertFalse(TypeUtils.isAssignable(paramType, testType),
749                 () -> String.format("TypeUtils.isAssignable(%s, %s)", paramType, testType));
750         assertFalse(TypeUtils.isAssignable(testType, paramType),
751                 () -> String.format("TypeUtils.isAssignable(%s, %s)", testType, paramType));
752     }
753 
754     @Test
755     @Disabled("TODO")
756     void testIsAssignableGenericArrayTypeToWildcardType() {
757         final Class<Constructor> rawClass = Constructor.class;
758         final Class<Insets> typeArgClass = Insets.class;
759         // Builds a ParameterizedType for Constructor<Insets>
760         final ParameterizedType paramType = TypeUtils.parameterize(rawClass, typeArgClass);
761         assertEquals(rawClass, paramType.getRawType());
762         assertEquals(typeArgClass, paramType.getActualTypeArguments()[0]);
763 
764         assertFalse(WildcardType.class.isAssignableFrom(paramType.getClass()));
765         assertFalse(paramType.getClass().isAssignableFrom(WildcardType.class));
766 
767         final WildcardType testType = TypeUtils.WILDCARD_ALL;
768         // TODO This test returns true unlike the test above.
769         // Is this a bug in this test or in the main code?
770         assertFalse(TypeUtils.isAssignable(paramType, testType),
771                 () -> String.format("TypeUtils.isAssignable(%s, %s)", paramType, testType));
772         assertFalse(TypeUtils.isAssignable(testType, paramType),
773                 () -> String.format("TypeUtils.isAssignable(%s, %s)", testType, paramType));
774     }
775 
776     @Test
777     void testIsAssignableGenericClassHierarchy() throws NoSuchFieldException {
778         /*
779          *            <<This>>
780          *      /      /     \     \
781          * <<And>>   That   Other   Tester
782          *      \   /         |
783          *       The        Thing
784          */
785         final Type disType = getClass().getField("dis").getGenericType();       // This is superinterface
786         final Type datType = getClass().getField("dat").getGenericType();       // That implements This
787         final Type dat2Type = getClass().getField("dat2").getGenericType();
788         final Type dat3Type = getClass().getField("dat3").getGenericType();
789         final Type daType = getClass().getField("da").getGenericType();         // The extends That and implements And
790         final Type uhderType = getClass().getField("uhder").getGenericType();   // Other implements This
791         final Type dingType = getClass().getField("ding").getGenericType();     // Thing extends Other
792         final Type testerType = getClass().getField("tester").getGenericType(); // Tester implements This
793         final Type tester2Type = getClass().getField("tester2").getGenericType();
794 
795         assertTrue(TypeUtils.isAssignable(datType, disType));
796         assertFalse(TypeUtils.isAssignable(daType, disType));
797         assertTrue(TypeUtils.isAssignable(uhderType, disType));
798         assertFalse(TypeUtils.isAssignable(dingType, disType));
799         assertTrue(TypeUtils.isAssignable(testerType, disType));
800         assertFalse(TypeUtils.isAssignable(tester2Type, disType));
801 
802         assertFalse(TypeUtils.isAssignable(dat2Type, datType));
803         assertFalse(TypeUtils.isAssignable(datType, dat2Type));
804         assertFalse(TypeUtils.isAssignable(dat3Type, datType));
805     }
806 
807     @Test
808     void testIsAssignableGenericComparableTypes() throws NoSuchFieldException {
809         final Type intComparableType = getClass().getField("intComparable").getGenericType();
810         assertTrue(TypeUtils.isAssignable(int.class, intComparableType));
811 
812         final Type longComparableType = getClass().getField("longComparable").getGenericType();
813         assertFalse(TypeUtils.isAssignable(int.class, longComparableType));
814         assertFalse(TypeUtils.isAssignable(Integer.class, longComparableType));
815 
816         final Type intComparableArrayType = getClass().getField("intWildcardComparable").getGenericType();
817         assertTrue(TypeUtils.isAssignable(Integer[].class, intComparableArrayType));
818     }
819 
820     @Test
821     void testIsAssignableGenericListArrays() throws NoSuchFieldException {
822         final Type rawListTypeArray = GenericTypeHolder.class.getDeclaredField("rawListArray").getGenericType();
823         final Type objectListTypeArray = GenericTypeHolder.class.getDeclaredField("objectListArray").getGenericType();
824         final Type unboundListTypeArray = GenericTypeHolder.class.getDeclaredField("unboundListArray").getGenericType();
825         final Type superObjectListTypeArray = GenericTypeHolder.class.getDeclaredField("superObjectListArray").getGenericType();
826         final Type stringListTypeArray = GenericTypeHolder.class.getDeclaredField("stringListArray").getGenericType();
827         final Type subStringListTypeArray = GenericTypeHolder.class.getDeclaredField("subStringListArray").getGenericType();
828         final Type superStringListTypeArray = GenericTypeHolder.class.getDeclaredField("superStringListArray").getGenericType();
829 
830         assertTrue(TypeUtils.isAssignable(rawListTypeArray, rawListTypeArray));
831         assertTrue(TypeUtils.isAssignable(rawListTypeArray, objectListTypeArray));
832         assertTrue(TypeUtils.isAssignable(objectListTypeArray, rawListTypeArray));
833         assertTrue(TypeUtils.isAssignable(rawListTypeArray, unboundListTypeArray));
834         assertTrue(TypeUtils.isAssignable(unboundListTypeArray, rawListTypeArray));
835         assertTrue(TypeUtils.isAssignable(rawListTypeArray, superObjectListTypeArray));
836         assertTrue(TypeUtils.isAssignable(superObjectListTypeArray, rawListTypeArray));
837         assertTrue(TypeUtils.isAssignable(rawListTypeArray, stringListTypeArray));
838         assertTrue(TypeUtils.isAssignable(stringListTypeArray, rawListTypeArray));
839         assertTrue(TypeUtils.isAssignable(rawListTypeArray, subStringListTypeArray));
840         assertTrue(TypeUtils.isAssignable(subStringListTypeArray, rawListTypeArray));
841         assertTrue(TypeUtils.isAssignable(rawListTypeArray, superStringListTypeArray));
842         assertTrue(TypeUtils.isAssignable(superStringListTypeArray, rawListTypeArray));
843 
844         assertTrue(TypeUtils.isAssignable(objectListTypeArray, objectListTypeArray));
845         assertTrue(TypeUtils.isAssignable(objectListTypeArray, unboundListTypeArray));
846         assertFalse(TypeUtils.isAssignable(unboundListTypeArray, objectListTypeArray));
847         assertTrue(TypeUtils.isAssignable(objectListTypeArray, superObjectListTypeArray));
848         assertFalse(TypeUtils.isAssignable(superObjectListTypeArray, objectListTypeArray));
849         assertFalse(TypeUtils.isAssignable(objectListTypeArray, stringListTypeArray));
850         assertFalse(TypeUtils.isAssignable(stringListTypeArray, objectListTypeArray));
851         assertFalse(TypeUtils.isAssignable(objectListTypeArray, subStringListTypeArray));
852         assertFalse(TypeUtils.isAssignable(subStringListTypeArray, objectListTypeArray));
853         assertTrue(TypeUtils.isAssignable(objectListTypeArray, superStringListTypeArray));
854         assertFalse(TypeUtils.isAssignable(superStringListTypeArray, objectListTypeArray));
855 
856         assertTrue(TypeUtils.isAssignable(unboundListTypeArray, unboundListTypeArray));
857         assertFalse(TypeUtils.isAssignable(unboundListTypeArray, superObjectListTypeArray));
858         assertTrue(TypeUtils.isAssignable(superObjectListTypeArray, unboundListTypeArray));
859         assertFalse(TypeUtils.isAssignable(unboundListTypeArray, stringListTypeArray));
860         assertTrue(TypeUtils.isAssignable(stringListTypeArray, unboundListTypeArray));
861         assertFalse(TypeUtils.isAssignable(unboundListTypeArray, subStringListTypeArray));
862         assertTrue(TypeUtils.isAssignable(subStringListTypeArray, unboundListTypeArray));
863         assertFalse(TypeUtils.isAssignable(unboundListTypeArray, superStringListTypeArray));
864         assertTrue(TypeUtils.isAssignable(superStringListTypeArray, unboundListTypeArray));
865 
866         assertTrue(TypeUtils.isAssignable(superObjectListTypeArray, superObjectListTypeArray));
867         assertFalse(TypeUtils.isAssignable(superObjectListTypeArray, stringListTypeArray));
868         assertFalse(TypeUtils.isAssignable(stringListTypeArray, superObjectListTypeArray));
869         assertFalse(TypeUtils.isAssignable(superObjectListTypeArray, subStringListTypeArray));
870         assertFalse(TypeUtils.isAssignable(subStringListTypeArray, superObjectListTypeArray));
871         assertTrue(TypeUtils.isAssignable(superObjectListTypeArray, superStringListTypeArray));
872         assertFalse(TypeUtils.isAssignable(superStringListTypeArray, superObjectListTypeArray));
873 
874         assertTrue(TypeUtils.isAssignable(stringListTypeArray, stringListTypeArray));
875         assertTrue(TypeUtils.isAssignable(stringListTypeArray, subStringListTypeArray));
876         assertFalse(TypeUtils.isAssignable(subStringListTypeArray, stringListTypeArray));
877         assertTrue(TypeUtils.isAssignable(stringListTypeArray, superStringListTypeArray));
878         assertFalse(TypeUtils.isAssignable(superStringListTypeArray, stringListTypeArray));
879 
880         assertTrue(TypeUtils.isAssignable(subStringListTypeArray, subStringListTypeArray));
881         assertFalse(TypeUtils.isAssignable(subStringListTypeArray, superStringListTypeArray));
882         assertFalse(TypeUtils.isAssignable(superStringListTypeArray, subStringListTypeArray));
883         assertTrue(TypeUtils.isAssignable(superStringListTypeArray, superStringListTypeArray));
884     }
885 
886     @Test
887     void testIsAssignableGenericListTypes() throws NoSuchFieldException {
888         final Type rawListType = GenericTypeHolder.class.getDeclaredField("rawList").getGenericType();
889         final Type objectListType = GenericTypeHolder.class.getDeclaredField("objectList").getGenericType();
890         final Type unboundListType = GenericTypeHolder.class.getDeclaredField("unboundList").getGenericType();
891         final Type superObjectListType = GenericTypeHolder.class.getDeclaredField("superObjectList").getGenericType();
892         final Type stringListType = GenericTypeHolder.class.getDeclaredField("stringList").getGenericType();
893         final Type subStringListType = GenericTypeHolder.class.getDeclaredField("subStringList").getGenericType();
894         final Type superStringListType = GenericTypeHolder.class.getDeclaredField("superStringList").getGenericType();
895 
896         assertTrue(TypeUtils.isAssignable(rawListType, rawListType));
897         assertTrue(TypeUtils.isAssignable(rawListType, objectListType));
898         assertTrue(TypeUtils.isAssignable(objectListType, rawListType));
899         assertTrue(TypeUtils.isAssignable(rawListType, unboundListType));
900         assertTrue(TypeUtils.isAssignable(unboundListType, rawListType));
901         assertTrue(TypeUtils.isAssignable(rawListType, superObjectListType));
902         assertTrue(TypeUtils.isAssignable(superObjectListType, rawListType));
903         assertTrue(TypeUtils.isAssignable(rawListType, stringListType));
904         assertTrue(TypeUtils.isAssignable(stringListType, rawListType));
905         assertTrue(TypeUtils.isAssignable(rawListType, subStringListType));
906         assertTrue(TypeUtils.isAssignable(subStringListType, rawListType));
907         assertTrue(TypeUtils.isAssignable(rawListType, superStringListType));
908         assertTrue(TypeUtils.isAssignable(superStringListType, rawListType));
909 
910         assertTrue(TypeUtils.isAssignable(objectListType, objectListType));
911         assertTrue(TypeUtils.isAssignable(objectListType, unboundListType));
912         assertFalse(TypeUtils.isAssignable(unboundListType, objectListType));
913         assertTrue(TypeUtils.isAssignable(objectListType, superObjectListType));
914         assertFalse(TypeUtils.isAssignable(superObjectListType, objectListType));
915         assertFalse(TypeUtils.isAssignable(objectListType, stringListType));
916         assertFalse(TypeUtils.isAssignable(stringListType, objectListType));
917         assertFalse(TypeUtils.isAssignable(objectListType, subStringListType));
918         assertFalse(TypeUtils.isAssignable(subStringListType, objectListType));
919         assertTrue(TypeUtils.isAssignable(objectListType, superStringListType));
920         assertFalse(TypeUtils.isAssignable(superStringListType, objectListType));
921 
922         assertTrue(TypeUtils.isAssignable(unboundListType, unboundListType));
923         assertFalse(TypeUtils.isAssignable(unboundListType, superObjectListType));
924         assertTrue(TypeUtils.isAssignable(superObjectListType, unboundListType));
925         assertFalse(TypeUtils.isAssignable(unboundListType, stringListType));
926         assertTrue(TypeUtils.isAssignable(stringListType, unboundListType));
927         assertFalse(TypeUtils.isAssignable(unboundListType, subStringListType));
928         assertTrue(TypeUtils.isAssignable(subStringListType, unboundListType));
929         assertFalse(TypeUtils.isAssignable(unboundListType, superStringListType));
930         assertTrue(TypeUtils.isAssignable(superStringListType, unboundListType));
931 
932         assertTrue(TypeUtils.isAssignable(superObjectListType, superObjectListType));
933         assertFalse(TypeUtils.isAssignable(superObjectListType, stringListType));
934         assertFalse(TypeUtils.isAssignable(stringListType, superObjectListType));
935         assertFalse(TypeUtils.isAssignable(superObjectListType, subStringListType));
936         assertFalse(TypeUtils.isAssignable(subStringListType, superObjectListType));
937         assertTrue(TypeUtils.isAssignable(superObjectListType, superStringListType));
938         assertFalse(TypeUtils.isAssignable(superStringListType, superObjectListType));
939 
940         assertTrue(TypeUtils.isAssignable(stringListType, stringListType));
941         assertTrue(TypeUtils.isAssignable(stringListType, subStringListType));
942         assertFalse(TypeUtils.isAssignable(subStringListType, stringListType));
943         assertTrue(TypeUtils.isAssignable(stringListType, superStringListType));
944         assertFalse(TypeUtils.isAssignable(superStringListType, stringListType));
945 
946         assertTrue(TypeUtils.isAssignable(subStringListType, subStringListType));
947         assertFalse(TypeUtils.isAssignable(subStringListType, superStringListType));
948         assertFalse(TypeUtils.isAssignable(superStringListType, subStringListType));
949         assertTrue(TypeUtils.isAssignable(superStringListType, superStringListType));
950     }
951 
952     @SuppressWarnings("boxing") // boxing is deliberate here
953     @Test
954     void testIsInstance() throws NoSuchFieldException {
955         assertFalse(TypeUtils.isInstance(1, null));
956         final Type intComparableType = getClass().getField("intComparable").getGenericType();
957         final Type uriComparableType = getClass().getField("uriComparable").getGenericType();
958         assertTrue(TypeUtils.isInstance(1, intComparableType));
959         assertFalse(TypeUtils.isInstance(1, uriComparableType));
960     }
961 
962     @Test
963     void testLowerBoundedWildcardType() {
964        final WildcardType lowerBounded = TypeUtils.wildcardType().withLowerBounds(java.sql.Date.class).build();
965        assertEquals(String.format("? super %s", java.sql.Date.class.getName()), TypeUtils.toString(lowerBounded));
966        assertEquals(String.format("? super %s", java.sql.Date.class.getName()), lowerBounded.toString());
967 
968        final TypeVariable<Class<Iterable>> iterableT0 = Iterable.class.getTypeParameters()[0];
969        final WildcardType lowerTypeVariable = TypeUtils.wildcardType().withLowerBounds(iterableT0).build();
970        assertEquals(String.format("? super %s", iterableT0.getName()), TypeUtils.toString(lowerTypeVariable));
971        assertEquals(String.format("? super %s", iterableT0.getName()), lowerTypeVariable.toString());
972     }
973 
974     @Test
975     void testNormalizeUpperBounds() {
976         final Type[] typeArray = { Collection.class, List.class };
977         final Type[] expectedArray = { List.class };
978         assertArrayEquals(expectedArray, TypeUtils.normalizeUpperBounds(typeArray));
979     }
980 
981     @Test
982     void testNormalizeUpperBounds_LANG_820() {
983         final Type[] typeArray = { String.class, String.class };
984         final Type[] expectedArray = { String.class };
985         assertArrayEquals(expectedArray, TypeUtils.normalizeUpperBounds(typeArray));
986     }
987 
988     @Test
989     void testParameterizeMapArg() throws NoSuchFieldException {
990         final Map<TypeVariable<?>, Type> typeVariableMap = new HashMap<>();
991         typeVariableMap.put(Comparable.class.getTypeParameters()[0], String.class);
992         final ParameterizedType stringComparableType = TypeUtils.parameterize(Comparable.class, typeVariableMap);
993         assertTrue(TypeUtils.equals(getClass().getField("stringComparable").getGenericType(), stringComparableType));
994         assertEquals("java.lang.Comparable<java.lang.String>", stringComparableType.toString());
995     }
996 
997     @Test
998     void testParameterizeNarrowerTypeArray() {
999         final TypeVariable<?>[] variables = ArrayList.class.getTypeParameters();
1000         final ParameterizedType parameterizedType = TypeUtils.parameterize(ArrayList.class, variables);
1001         final Map<TypeVariable<?>, Type> mapping = Collections.<TypeVariable<?>, Type>singletonMap(variables[0], String.class);
1002         final Type unrolled = TypeUtils.unrollVariables(mapping, parameterizedType);
1003         assertEquals(TypeUtils.parameterize(ArrayList.class, String.class), unrolled);
1004     }
1005 
1006     @Test
1007     void testParameterizeNullPointerException() {
1008         assertNullPointerException(() -> TypeUtils.parameterize(null, Collections.emptyMap()));
1009         final Map<TypeVariable<?>, Type> nullTypeVariableMap = null;
1010         assertNullPointerException(() -> TypeUtils.parameterize(String.class, nullTypeVariableMap));
1011     }
1012 
1013     @Test
1014     void testParameterizeVarArgs() throws NoSuchFieldException {
1015         final ParameterizedType stringComparableType = TypeUtils.parameterize(Comparable.class, String.class);
1016         assertTrue(TypeUtils.equals(getClass().getField("stringComparable").getGenericType(), stringComparableType));
1017         assertEquals("java.lang.Comparable<java.lang.String>", stringComparableType.toString());
1018     }
1019 
1020     @Test
1021     void testParameterizeVarArgsNullPointerException() {
1022         assertNullPointerException(() -> TypeUtils.parameterize(null));
1023     }
1024 
1025     @SuppressWarnings("unlikely-arg-type")
1026     @Test
1027     void testParameterizeWithOwner() throws NoSuchFieldException {
1028         final Type owner = TypeUtils.parameterize(TypeUtilsTest.class, String.class);
1029         final ParameterizedType dat2Type1 = TypeUtils.parameterizeWithOwner(owner, That.class, String.class, String.class);
1030         assertTrue(TypeUtils.equals(getClass().getField("dat2").getGenericType(), dat2Type1));
1031         assertNotEquals(0, dat2Type1.hashCode());
1032         assertEquals(dat2Type1, dat2Type1);
1033         final ParameterizedType dat2Type2 = TypeUtils.parameterizeWithOwner(null, That.class, String.class, String.class);
1034         assertEquals(That.class, dat2Type2.getRawType());
1035         assertNotEquals(0, dat2Type2.hashCode());
1036         assertEquals(dat2Type2, dat2Type2);
1037         assertNotEquals(dat2Type2, dat2Type1);
1038         assertFalse(dat2Type1.equals(null));
1039         assertFalse(dat2Type1.equals(TypeUtils.genericArrayType(String.class)));
1040     }
1041 
1042     @Test
1043     void testParameterizeWithOwner3ArgsNullPointerException() {
1044         final Type owner = TypeUtils.parameterize(TypeUtilsTest.class, String.class);
1045         assertNullPointerException(() -> TypeUtils.parameterizeWithOwner(owner, null, String.class));
1046         final Map<TypeVariable<?>, Type> nullTypeVariableMap = null;
1047         assertNullPointerException(() -> TypeUtils.parameterizeWithOwner(owner, That.class, nullTypeVariableMap));
1048         final Map<TypeVariable<?>, Type> typeVariableMap1 = new HashMap<>();
1049         typeVariableMap1.put(Comparable.class.getTypeParameters()[0], String.class);
1050         assertEquals(Comparable.class, TypeUtils.parameterizeWithOwner(null, Comparable.class, typeVariableMap1).getRawType());
1051         final Map<TypeVariable<?>, Type> typeVariableMap2 = new HashMap<>();
1052         typeVariableMap2.put(MyInnerClass.class.getTypeParameters()[0], String.class);
1053         assertEquals(MyInnerClass.class, TypeUtils.parameterizeWithOwner(null, MyInnerClass.class, typeVariableMap2).getRawType());
1054         assertEquals(MyInnerClass.class, TypeUtils.parameterizeWithOwner(owner, MyInnerClass.class, typeVariableMap2).getRawType());
1055     }
1056 
1057     @Test
1058     void testParameterizeWithOwnerVarArgsNullPointerException() {
1059         final Type owner = TypeUtils.parameterize(TypeUtilsTest.class, String.class);
1060         assertNullPointerException(() -> TypeUtils.parameterizeWithOwner(owner, null));
1061     }
1062 
1063     @Test
1064     void testToLongString() {
1065         assertNullPointerException(() -> TypeUtils.toLongString(null));
1066         assertEquals(getClass().getName() + ":B", TypeUtils.toLongString(getClass().getTypeParameters()[0]));
1067         assertEquals(getClass().getName() + ".MyInnerClass:T", TypeUtils.toLongString(MyInnerClass.class.getTypeParameters()[0]));
1068         assertEquals(getClass().getName() + ".That:K", TypeUtils.toLongString(That.class.getTypeParameters()[0]));
1069         assertEquals(getClass().getName() + ".The:K", TypeUtils.toLongString(The.class.getTypeParameters()[0]));
1070         assertEquals(getClass().getName() + ".MyInnerClass.MyInnerClass2:X", TypeUtils.toLongString(MyInnerClass.MyInnerClass2.class.getTypeParameters()[0]));
1071     }
1072 
1073     @Test
1074     void testToString() {
1075         assertNullPointerException(() -> TypeUtils.toString(null));
1076         assertIllegalArgumentException(() -> TypeUtils.toString(new Type() {
1077             // empty
1078         }));
1079     }
1080 
1081     @Test
1082     void testToString_LANG_1311() {
1083         assertEquals("int[]", TypeUtils.toString(int[].class));
1084         assertEquals("java.lang.Integer[]", TypeUtils.toString(Integer[].class));
1085         final Field stringListField = FieldUtils.getDeclaredField(getClass(), "stringListArray");
1086         assertEquals("java.util.List<java.lang.String>[]", TypeUtils.toString(stringListField.getGenericType()));
1087     }
1088 
1089     @Test
1090     void testTypesSatisfyVariables() throws NoSuchMethodException {
1091         final Map<TypeVariable<?>, Type> typeVarAssigns = new HashMap<>();
1092         final Integer max = TypeUtilsTest.<Integer>stub();
1093         typeVarAssigns.put(getClass().getMethod("stub").getTypeParameters()[0], Integer.class);
1094         assertTrue(TypeUtils.typesSatisfyVariables(typeVarAssigns));
1095         typeVarAssigns.clear();
1096         typeVarAssigns.put(getClass().getMethod("stub2").getTypeParameters()[0], Integer.class);
1097         assertTrue(TypeUtils.typesSatisfyVariables(typeVarAssigns));
1098         typeVarAssigns.clear();
1099         typeVarAssigns.put(getClass().getMethod("stub3").getTypeParameters()[0], Integer.class);
1100         assertTrue(TypeUtils.typesSatisfyVariables(typeVarAssigns));
1101         assertNullPointerException(() -> TypeUtils.typesSatisfyVariables(null));
1102     }
1103 
1104     @ParameterizedTest
1105     @MethodSource
1106     void testTypeToString(final Type type) {
1107         // No stack overflow
1108         assertNotNull(TypeUtils.toString(type));
1109     }
1110 
1111     @Test
1112     void testUnboundedWildcardType() {
1113         final WildcardType unbounded = TypeUtils.wildcardType().withLowerBounds((Type) null).withUpperBounds().build();
1114         assertTrue(TypeUtils.equals(TypeUtils.WILDCARD_ALL, unbounded));
1115         assertArrayEquals(new Type[] { Object.class }, TypeUtils.getImplicitUpperBounds(unbounded));
1116         assertArrayEquals(new Type[] { null }, TypeUtils.getImplicitLowerBounds(unbounded));
1117         assertEquals("?", TypeUtils.toString(unbounded));
1118         assertEquals("?", unbounded.toString());
1119         assertNullPointerException(() -> TypeUtils.getImplicitLowerBounds(null));
1120         assertNullPointerException(() -> TypeUtils.getImplicitUpperBounds(null));
1121     }
1122 
1123     @Test
1124     void testUnrollVariables() {
1125         final TypeVariable<?>[] variables = ArrayList.class.getTypeParameters();
1126         final ParameterizedType parameterizedType = TypeUtils.parameterize(ArrayList.class, variables);
1127         assertEquals("java.util.ArrayList<E>", TypeUtils.unrollVariables(null, parameterizedType).getTypeName());
1128         final Map<TypeVariable<?>, Type> mapping = Collections.<TypeVariable<?>, Type>singletonMap(variables[0], String.class);
1129         assertEquals("java.util.ArrayList<java.lang.String>", TypeUtils.unrollVariables(mapping, parameterizedType).getTypeName());
1130     }
1131 
1132     @SuppressWarnings("unlikely-arg-type")
1133     @Test
1134     void testWildcardType() throws NoSuchFieldException {
1135         final WildcardType simpleWildcard = TypeUtils.wildcardType().withUpperBounds(String.class).build();
1136         final Field cClass = AClass.class.getField("cClass");
1137         assertTrue(TypeUtils.equals(((ParameterizedType) cClass.getGenericType()).getActualTypeArguments()[0], simpleWildcard));
1138         assertEquals(String.format("? extends %s", String.class.getName()), TypeUtils.toString(simpleWildcard));
1139         assertEquals(String.format("? extends %s", String.class.getName()), simpleWildcard.toString());
1140         assertNotEquals(0, simpleWildcard.hashCode());
1141         assertEquals(simpleWildcard, simpleWildcard);
1142         assertFalse(simpleWildcard.equals(null));
1143         assertFalse(simpleWildcard.equals(TypeUtils.genericArrayType(String.class)));
1144     }
1145 
1146     @Test
1147     void testWrap() {
1148         final Type t = getClass().getTypeParameters()[0];
1149         assertTrue(TypeUtils.equals(t, TypeUtils.wrap(t).getType()));
1150         assertEquals(String.class, TypeUtils.wrap(String.class).getType());
1151     }
1152 }