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