001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.lang3.reflect;
018
019import java.lang.reflect.Array;
020import java.lang.reflect.GenericArrayType;
021import java.lang.reflect.GenericDeclaration;
022import java.lang.reflect.ParameterizedType;
023import java.lang.reflect.Type;
024import java.lang.reflect.TypeVariable;
025import java.lang.reflect.WildcardType;
026import java.util.Arrays;
027import java.util.Collections;
028import java.util.HashMap;
029import java.util.HashSet;
030import java.util.List;
031import java.util.Map;
032import java.util.Objects;
033import java.util.Set;
034
035import org.apache.commons.lang3.ArrayUtils;
036import org.apache.commons.lang3.ClassUtils;
037import org.apache.commons.lang3.ObjectUtils;
038import org.apache.commons.lang3.Validate;
039import org.apache.commons.lang3.builder.Builder;
040
041/**
042 * <p> Utility methods focusing on type inspection, particularly with regard to
043 * generics. </p>
044 *
045 * @since 3.0
046 */
047public class TypeUtils {
048
049    /**
050     * {@link WildcardType} builder.
051     * @since 3.2
052     */
053    public static class WildcardTypeBuilder implements Builder<WildcardType> {
054        /**
055         * Constructor
056         */
057        private WildcardTypeBuilder() {
058        }
059
060        private Type[] upperBounds;
061        private Type[] lowerBounds;
062
063        /**
064         * Specify upper bounds of the wildcard type to build.
065         * @param bounds to set
066         * @return {@code this}
067         */
068        public WildcardTypeBuilder withUpperBounds(final Type... bounds) {
069            this.upperBounds = bounds;
070            return this;
071        }
072
073        /**
074         * Specify lower bounds of the wildcard type to build.
075         * @param bounds to set
076         * @return {@code this}
077         */
078        public WildcardTypeBuilder withLowerBounds(final Type... bounds) {
079            this.lowerBounds = bounds;
080            return this;
081        }
082
083        /**
084         * {@inheritDoc}
085         */
086        @Override
087        public WildcardType build() {
088            return new WildcardTypeImpl(upperBounds, lowerBounds);
089        }
090    }
091
092    /**
093     * GenericArrayType implementation class.
094     * @since 3.2
095     */
096    private static final class GenericArrayTypeImpl implements GenericArrayType {
097        private final Type componentType;
098
099        /**
100         * Constructor
101         * @param componentType of this array type
102         */
103        private GenericArrayTypeImpl(final Type componentType) {
104            this.componentType = componentType;
105        }
106
107        /**
108         * {@inheritDoc}
109         */
110        @Override
111        public Type getGenericComponentType() {
112            return componentType;
113        }
114
115        /**
116         * {@inheritDoc}
117         */
118        @Override
119        public String toString() {
120            return TypeUtils.toString(this);
121        }
122
123        /**
124         * {@inheritDoc}
125         */
126        @Override
127        public boolean equals(final Object obj) {
128            return obj == this || obj instanceof GenericArrayType && TypeUtils.equals(this, (GenericArrayType) obj);
129        }
130
131        /**
132         * {@inheritDoc}
133         */
134        @Override
135        public int hashCode() {
136            int result = 67 << 4;
137            result |= componentType.hashCode();
138            return result;
139        }
140    }
141
142    /**
143     * ParameterizedType implementation class.
144     * @since 3.2
145     */
146    private static final class ParameterizedTypeImpl implements ParameterizedType {
147        private final Class<?> raw;
148        private final Type useOwner;
149        private final Type[] typeArguments;
150
151        /**
152         * Constructor
153         * @param rawClass type
154         * @param useOwner owner type to use, if any
155         * @param typeArguments formal type arguments
156         */
157        private ParameterizedTypeImpl(final Class<?> rawClass, final Type useOwner, final Type[] typeArguments) {
158            this.raw = rawClass;
159            this.useOwner = useOwner;
160            this.typeArguments = Arrays.copyOf(typeArguments, typeArguments.length, Type[].class);
161        }
162
163        /**
164         * {@inheritDoc}
165         */
166        @Override
167        public Type getRawType() {
168            return raw;
169        }
170
171        /**
172         * {@inheritDoc}
173         */
174        @Override
175        public Type getOwnerType() {
176            return useOwner;
177        }
178
179        /**
180         * {@inheritDoc}
181         */
182        @Override
183        public Type[] getActualTypeArguments() {
184            return typeArguments.clone();
185        }
186
187        /**
188         * {@inheritDoc}
189         */
190        @Override
191        public String toString() {
192            return TypeUtils.toString(this);
193        }
194
195        /**
196         * {@inheritDoc}
197         */
198        @Override
199        public boolean equals(final Object obj) {
200            return obj == this || obj instanceof ParameterizedType && TypeUtils.equals(this, ((ParameterizedType) obj));
201        }
202
203        /**
204         * {@inheritDoc}
205         */
206        @Override
207        public int hashCode() {
208            int result = 71 << 4;
209            result |= raw.hashCode();
210            result <<= 4;
211            result |= Objects.hashCode(useOwner);
212            result <<= 8;
213            result |= Arrays.hashCode(typeArguments);
214            return result;
215        }
216    }
217
218    /**
219     * WildcardType implementation class.
220     * @since 3.2
221     */
222    private static final class WildcardTypeImpl implements WildcardType {
223        private final Type[] upperBounds;
224        private final Type[] lowerBounds;
225
226        /**
227         * Constructor
228         * @param upperBounds of this type
229         * @param lowerBounds of this type
230         */
231        private WildcardTypeImpl(final Type[] upperBounds, final Type[] lowerBounds) {
232            this.upperBounds = ObjectUtils.defaultIfNull(upperBounds, ArrayUtils.EMPTY_TYPE_ARRAY);
233            this.lowerBounds = ObjectUtils.defaultIfNull(lowerBounds, ArrayUtils.EMPTY_TYPE_ARRAY);
234        }
235
236        /**
237         * {@inheritDoc}
238         */
239        @Override
240        public Type[] getUpperBounds() {
241            return upperBounds.clone();
242        }
243
244        /**
245         * {@inheritDoc}
246         */
247        @Override
248        public Type[] getLowerBounds() {
249            return lowerBounds.clone();
250        }
251
252        /**
253         * {@inheritDoc}
254         */
255        @Override
256        public String toString() {
257            return TypeUtils.toString(this);
258        }
259
260        /**
261         * {@inheritDoc}
262         */
263        @Override
264        public boolean equals(final Object obj) {
265            return obj == this || obj instanceof WildcardType && TypeUtils.equals(this, (WildcardType) obj);
266        }
267
268        /**
269         * {@inheritDoc}
270         */
271        @Override
272        public int hashCode() {
273            int result = 73 << 8;
274            result |= Arrays.hashCode(upperBounds);
275            result <<= 8;
276            result |= Arrays.hashCode(lowerBounds);
277            return result;
278        }
279    }
280
281    /**
282     * A wildcard instance matching {@code ?}.
283     * @since 3.2
284     */
285    public static final WildcardType WILDCARD_ALL = wildcardType().withUpperBounds(Object.class).build();
286
287    /**
288     * <p>{@code TypeUtils} instances should NOT be constructed in standard
289     * programming. Instead, the class should be used as
290     * {@code TypeUtils.isAssignable(cls, toClass)}.</p> <p>This
291     * constructor is public to permit tools that require a JavaBean instance to
292     * operate.</p>
293     */
294    public TypeUtils() {
295        super();
296    }
297
298    /**
299     * <p>Checks if the subject type may be implicitly cast to the target type
300     * following the Java generics rules. If both types are {@link Class}
301     * objects, the method returns the result of
302     * {@link ClassUtils#isAssignable(Class, Class)}.</p>
303     *
304     * @param type the subject type to be assigned to the target type
305     * @param toType the target type
306     * @return {@code true} if {@code type} is assignable to {@code toType}.
307     */
308    public static boolean isAssignable(final Type type, final Type toType) {
309        return isAssignable(type, toType, null);
310    }
311
312    /**
313     * <p>Checks if the subject type may be implicitly cast to the target type
314     * following the Java generics rules.</p>
315     *
316     * @param type the subject type to be assigned to the target type
317     * @param toType the target type
318     * @param typeVarAssigns optional map of type variable assignments
319     * @return {@code true} if {@code type} is assignable to {@code toType}.
320     */
321    private static boolean isAssignable(final Type type, final Type toType,
322            final Map<TypeVariable<?>, Type> typeVarAssigns) {
323        if (toType == null || toType instanceof Class<?>) {
324            return isAssignable(type, (Class<?>) toType);
325        }
326
327        if (toType instanceof ParameterizedType) {
328            return isAssignable(type, (ParameterizedType) toType, typeVarAssigns);
329        }
330
331        if (toType instanceof GenericArrayType) {
332            return isAssignable(type, (GenericArrayType) toType, typeVarAssigns);
333        }
334
335        if (toType instanceof WildcardType) {
336            return isAssignable(type, (WildcardType) toType, typeVarAssigns);
337        }
338
339        if (toType instanceof TypeVariable<?>) {
340            return isAssignable(type, (TypeVariable<?>) toType, typeVarAssigns);
341        }
342
343        throw new IllegalStateException("found an unhandled type: " + toType);
344    }
345
346    /**
347     * <p>Checks if the subject type may be implicitly cast to the target class
348     * following the Java generics rules.</p>
349     *
350     * @param type the subject type to be assigned to the target type
351     * @param toClass the target class
352     * @return {@code true} if {@code type} is assignable to {@code toClass}.
353     */
354    private static boolean isAssignable(final Type type, final Class<?> toClass) {
355        if (type == null) {
356            // consistency with ClassUtils.isAssignable() behavior
357            return toClass == null || !toClass.isPrimitive();
358        }
359
360        // only a null type can be assigned to null type which
361        // would have cause the previous to return true
362        if (toClass == null) {
363            return false;
364        }
365
366        // all types are assignable to themselves
367        if (toClass.equals(type)) {
368            return true;
369        }
370
371        if (type instanceof Class<?>) {
372            // just comparing two classes
373            return ClassUtils.isAssignable((Class<?>) type, toClass);
374        }
375
376        if (type instanceof ParameterizedType) {
377            // only have to compare the raw type to the class
378            return isAssignable(getRawType((ParameterizedType) type), toClass);
379        }
380
381        // *
382        if (type instanceof TypeVariable<?>) {
383            // if any of the bounds are assignable to the class, then the
384            // type is assignable to the class.
385            for (final Type bound : ((TypeVariable<?>) type).getBounds()) {
386                if (isAssignable(bound, toClass)) {
387                    return true;
388                }
389            }
390
391            return false;
392        }
393
394        // the only classes to which a generic array type can be assigned
395        // are class Object and array classes
396        if (type instanceof GenericArrayType) {
397            return toClass.equals(Object.class)
398                    || toClass.isArray()
399                    && isAssignable(((GenericArrayType) type).getGenericComponentType(), toClass
400                            .getComponentType());
401        }
402
403        // wildcard types are not assignable to a class (though one would think
404        // "? super Object" would be assignable to Object)
405        if (type instanceof WildcardType) {
406            return false;
407        }
408
409        throw new IllegalStateException("found an unhandled type: " + type);
410    }
411
412    /**
413     * <p>Checks if the subject type may be implicitly cast to the target
414     * parameterized type following the Java generics rules.</p>
415     *
416     * @param type the subject type to be assigned to the target type
417     * @param toParameterizedType the target parameterized type
418     * @param typeVarAssigns a map with type variables
419     * @return {@code true} if {@code type} is assignable to {@code toType}.
420     */
421    private static boolean isAssignable(final Type type, final ParameterizedType toParameterizedType,
422            final Map<TypeVariable<?>, Type> typeVarAssigns) {
423        if (type == null) {
424            return true;
425        }
426
427        // only a null type can be assigned to null type which
428        // would have cause the previous to return true
429        if (toParameterizedType == null) {
430            return false;
431        }
432
433        // all types are assignable to themselves
434        if (toParameterizedType.equals(type)) {
435            return true;
436        }
437
438        // get the target type's raw type
439        final Class<?> toClass = getRawType(toParameterizedType);
440        // get the subject type's type arguments including owner type arguments
441        // and supertype arguments up to and including the target class.
442        final Map<TypeVariable<?>, Type> fromTypeVarAssigns = getTypeArguments(type, toClass, null);
443
444        // null means the two types are not compatible
445        if (fromTypeVarAssigns == null) {
446            return false;
447        }
448
449        // compatible types, but there's no type arguments. this is equivalent
450        // to comparing Map< ?, ? > to Map, and raw types are always assignable
451        // to parameterized types.
452        if (fromTypeVarAssigns.isEmpty()) {
453            return true;
454        }
455
456        // get the target type's type arguments including owner type arguments
457        final Map<TypeVariable<?>, Type> toTypeVarAssigns = getTypeArguments(toParameterizedType,
458                toClass, typeVarAssigns);
459
460        // now to check each type argument
461        for (final TypeVariable<?> var : toTypeVarAssigns.keySet()) {
462            final Type toTypeArg = unrollVariableAssignments(var, toTypeVarAssigns);
463            final Type fromTypeArg = unrollVariableAssignments(var, fromTypeVarAssigns);
464
465            if (toTypeArg == null && fromTypeArg instanceof Class) {
466                continue;
467            }
468
469            // parameters must either be absent from the subject type, within
470            // the bounds of the wildcard type, or be an exact match to the
471            // parameters of the target type.
472            if (fromTypeArg != null
473                    && !toTypeArg.equals(fromTypeArg)
474                    && !(toTypeArg instanceof WildcardType && isAssignable(fromTypeArg, toTypeArg,
475                            typeVarAssigns))) {
476                return false;
477            }
478        }
479        return true;
480    }
481
482    /**
483     * Look up {@code var} in {@code typeVarAssigns} <em>transitively</em>,
484     * i.e. keep looking until the value found is <em>not</em> a type variable.
485     * @param typeVariable the type variable to look up
486     * @param typeVarAssigns the map used for the look up
487     * @return Type or {@code null} if some variable was not in the map
488     * @since 3.2
489     */
490    private static Type unrollVariableAssignments(TypeVariable<?> typeVariable,
491        final Map<TypeVariable<?>, Type> typeVarAssigns) {
492        Type result;
493        do {
494            result = typeVarAssigns.get(typeVariable);
495            if (result instanceof TypeVariable<?> && !result.equals(typeVariable)) {
496                typeVariable = (TypeVariable<?>) result;
497                continue;
498            }
499            break;
500        } while (true);
501        return result;
502    }
503
504    /**
505     * <p>Checks if the subject type may be implicitly cast to the target
506     * generic array type following the Java generics rules.</p>
507     *
508     * @param type the subject type to be assigned to the target type
509     * @param toGenericArrayType the target generic array type
510     * @param typeVarAssigns a map with type variables
511     * @return {@code true} if {@code type} is assignable to
512     * {@code toGenericArrayType}.
513     */
514    private static boolean isAssignable(final Type type, final GenericArrayType toGenericArrayType,
515            final Map<TypeVariable<?>, Type> typeVarAssigns) {
516        if (type == null) {
517            return true;
518        }
519
520        // only a null type can be assigned to null type which
521        // would have cause the previous to return true
522        if (toGenericArrayType == null) {
523            return false;
524        }
525
526        // all types are assignable to themselves
527        if (toGenericArrayType.equals(type)) {
528            return true;
529        }
530
531        final Type toComponentType = toGenericArrayType.getGenericComponentType();
532
533        if (type instanceof Class<?>) {
534            final Class<?> cls = (Class<?>) type;
535
536            // compare the component types
537            return cls.isArray()
538                    && isAssignable(cls.getComponentType(), toComponentType, typeVarAssigns);
539        }
540
541        if (type instanceof GenericArrayType) {
542            // compare the component types
543            return isAssignable(((GenericArrayType) type).getGenericComponentType(),
544                    toComponentType, typeVarAssigns);
545        }
546
547        if (type instanceof WildcardType) {
548            // so long as one of the upper bounds is assignable, it's good
549            for (final Type bound : getImplicitUpperBounds((WildcardType) type)) {
550                if (isAssignable(bound, toGenericArrayType)) {
551                    return true;
552                }
553            }
554
555            return false;
556        }
557
558        if (type instanceof TypeVariable<?>) {
559            // probably should remove the following logic and just return false.
560            // type variables cannot specify arrays as bounds.
561            for (final Type bound : getImplicitBounds((TypeVariable<?>) type)) {
562                if (isAssignable(bound, toGenericArrayType)) {
563                    return true;
564                }
565            }
566
567            return false;
568        }
569
570        if (type instanceof ParameterizedType) {
571            // the raw type of a parameterized type is never an array or
572            // generic array, otherwise the declaration would look like this:
573            // Collection[]< ? extends String > collection;
574            return false;
575        }
576
577        throw new IllegalStateException("found an unhandled type: " + type);
578    }
579
580    /**
581     * <p>Checks if the subject type may be implicitly cast to the target
582     * wildcard type following the Java generics rules.</p>
583     *
584     * @param type the subject type to be assigned to the target type
585     * @param toWildcardType the target wildcard type
586     * @param typeVarAssigns a map with type variables
587     * @return {@code true} if {@code type} is assignable to
588     * {@code toWildcardType}.
589     */
590    private static boolean isAssignable(final Type type, final WildcardType toWildcardType,
591            final Map<TypeVariable<?>, Type> typeVarAssigns) {
592        if (type == null) {
593            return true;
594        }
595
596        // only a null type can be assigned to null type which
597        // would have cause the previous to return true
598        if (toWildcardType == null) {
599            return false;
600        }
601
602        // all types are assignable to themselves
603        if (toWildcardType.equals(type)) {
604            return true;
605        }
606
607        final Type[] toUpperBounds = getImplicitUpperBounds(toWildcardType);
608        final Type[] toLowerBounds = getImplicitLowerBounds(toWildcardType);
609
610        if (type instanceof WildcardType) {
611            final WildcardType wildcardType = (WildcardType) type;
612            final Type[] upperBounds = getImplicitUpperBounds(wildcardType);
613            final Type[] lowerBounds = getImplicitLowerBounds(wildcardType);
614
615            for (Type toBound : toUpperBounds) {
616                // if there are assignments for unresolved type variables,
617                // now's the time to substitute them.
618                toBound = substituteTypeVariables(toBound, typeVarAssigns);
619
620                // each upper bound of the subject type has to be assignable to
621                // each
622                // upper bound of the target type
623                for (final Type bound : upperBounds) {
624                    if (!isAssignable(bound, toBound, typeVarAssigns)) {
625                        return false;
626                    }
627                }
628            }
629
630            for (Type toBound : toLowerBounds) {
631                // if there are assignments for unresolved type variables,
632                // now's the time to substitute them.
633                toBound = substituteTypeVariables(toBound, typeVarAssigns);
634
635                // each lower bound of the target type has to be assignable to
636                // each
637                // lower bound of the subject type
638                for (final Type bound : lowerBounds) {
639                    if (!isAssignable(toBound, bound, typeVarAssigns)) {
640                        return false;
641                    }
642                }
643            }
644            return true;
645        }
646
647        for (final Type toBound : toUpperBounds) {
648            // if there are assignments for unresolved type variables,
649            // now's the time to substitute them.
650            if (!isAssignable(type, substituteTypeVariables(toBound, typeVarAssigns),
651                    typeVarAssigns)) {
652                return false;
653            }
654        }
655
656        for (final Type toBound : toLowerBounds) {
657            // if there are assignments for unresolved type variables,
658            // now's the time to substitute them.
659            if (!isAssignable(substituteTypeVariables(toBound, typeVarAssigns), type,
660                    typeVarAssigns)) {
661                return false;
662            }
663        }
664        return true;
665    }
666
667    /**
668     * <p>Checks if the subject type may be implicitly cast to the target type
669     * variable following the Java generics rules.</p>
670     *
671     * @param type the subject type to be assigned to the target type
672     * @param toTypeVariable the target type variable
673     * @param typeVarAssigns a map with type variables
674     * @return {@code true} if {@code type} is assignable to
675     * {@code toTypeVariable}.
676     */
677    private static boolean isAssignable(final Type type, final TypeVariable<?> toTypeVariable,
678            final Map<TypeVariable<?>, Type> typeVarAssigns) {
679        if (type == null) {
680            return true;
681        }
682
683        // only a null type can be assigned to null type which
684        // would have cause the previous to return true
685        if (toTypeVariable == null) {
686            return false;
687        }
688
689        // all types are assignable to themselves
690        if (toTypeVariable.equals(type)) {
691            return true;
692        }
693
694        if (type instanceof TypeVariable<?>) {
695            // a type variable is assignable to another type variable, if
696            // and only if the former is the latter, extends the latter, or
697            // is otherwise a descendant of the latter.
698            final Type[] bounds = getImplicitBounds((TypeVariable<?>) type);
699
700            for (final Type bound : bounds) {
701                if (isAssignable(bound, toTypeVariable, typeVarAssigns)) {
702                    return true;
703                }
704            }
705        }
706
707        if (type instanceof Class<?> || type instanceof ParameterizedType
708                || type instanceof GenericArrayType || type instanceof WildcardType) {
709            return false;
710        }
711
712        throw new IllegalStateException("found an unhandled type: " + type);
713    }
714
715    /**
716     * <p>Find the mapping for {@code type} in {@code typeVarAssigns}.</p>
717     *
718     * @param type the type to be replaced
719     * @param typeVarAssigns the map with type variables
720     * @return the replaced type
721     * @throws IllegalArgumentException if the type cannot be substituted
722     */
723    private static Type substituteTypeVariables(final Type type, final Map<TypeVariable<?>, Type> typeVarAssigns) {
724        if (type instanceof TypeVariable<?> && typeVarAssigns != null) {
725            final Type replacementType = typeVarAssigns.get(type);
726
727            if (replacementType == null) {
728                throw new IllegalArgumentException("missing assignment type for type variable "
729                        + type);
730            }
731            return replacementType;
732        }
733        return type;
734    }
735
736    /**
737     * <p>Retrieves all the type arguments for this parameterized type
738     * including owner hierarchy arguments such as
739     * {@code Outer<K, V>.Inner<T>.DeepInner<E>} .
740     * The arguments are returned in a
741     * {@link Map} specifying the argument type for each {@link TypeVariable}.
742     * </p>
743     *
744     * @param type specifies the subject parameterized type from which to
745     *             harvest the parameters.
746     * @return a {@code Map} of the type arguments to their respective type
747     * variables.
748     */
749    public static Map<TypeVariable<?>, Type> getTypeArguments(final ParameterizedType type) {
750        return getTypeArguments(type, getRawType(type), null);
751    }
752
753    /**
754     * <p>Gets the type arguments of a class/interface based on a subtype. For
755     * instance, this method will determine that both of the parameters for the
756     * interface {@link Map} are {@link Object} for the subtype
757     * {@link java.util.Properties Properties} even though the subtype does not
758     * directly implement the {@code Map} interface.</p>
759     * <p>This method returns {@code null} if {@code type} is not assignable to
760     * {@code toClass}. It returns an empty map if none of the classes or
761     * interfaces in its inheritance hierarchy specify any type arguments.</p>
762     * <p>A side effect of this method is that it also retrieves the type
763     * arguments for the classes and interfaces that are part of the hierarchy
764     * between {@code type} and {@code toClass}. So with the above
765     * example, this method will also determine that the type arguments for
766     * {@link java.util.Hashtable Hashtable} are also both {@code Object}.
767     * In cases where the interface specified by {@code toClass} is
768     * (indirectly) implemented more than once (e.g. where {@code toClass}
769     * specifies the interface {@link java.lang.Iterable Iterable} and
770     * {@code type} specifies a parameterized type that implements both
771     * {@link java.util.Set Set} and {@link java.util.Collection Collection}),
772     * this method will look at the inheritance hierarchy of only one of the
773     * implementations/subclasses; the first interface encountered that isn't a
774     * subinterface to one of the others in the {@code type} to
775     * {@code toClass} hierarchy.</p>
776     *
777     * @param type the type from which to determine the type parameters of
778     * {@code toClass}
779     * @param toClass the class whose type parameters are to be determined based
780     * on the subtype {@code type}
781     * @return a {@code Map} of the type assignments for the type variables in
782     * each type in the inheritance hierarchy from {@code type} to
783     * {@code toClass} inclusive.
784     */
785    public static Map<TypeVariable<?>, Type> getTypeArguments(final Type type, final Class<?> toClass) {
786        return getTypeArguments(type, toClass, null);
787    }
788
789    /**
790     * <p>Return a map of the type arguments of {@code type} in the context of {@code toClass}.</p>
791     *
792     * @param type the type in question
793     * @param toClass the class
794     * @param subtypeVarAssigns a map with type variables
795     * @return the {@code Map} with type arguments
796     */
797    private static Map<TypeVariable<?>, Type> getTypeArguments(final Type type, final Class<?> toClass,
798            final Map<TypeVariable<?>, Type> subtypeVarAssigns) {
799        if (type instanceof Class<?>) {
800            return getTypeArguments((Class<?>) type, toClass, subtypeVarAssigns);
801        }
802
803        if (type instanceof ParameterizedType) {
804            return getTypeArguments((ParameterizedType) type, toClass, subtypeVarAssigns);
805        }
806
807        if (type instanceof GenericArrayType) {
808            return getTypeArguments(((GenericArrayType) type).getGenericComponentType(), toClass
809                    .isArray() ? toClass.getComponentType() : toClass, subtypeVarAssigns);
810        }
811
812        // since wildcard types are not assignable to classes, should this just
813        // return null?
814        if (type instanceof WildcardType) {
815            for (final Type bound : getImplicitUpperBounds((WildcardType) type)) {
816                // find the first bound that is assignable to the target class
817                if (isAssignable(bound, toClass)) {
818                    return getTypeArguments(bound, toClass, subtypeVarAssigns);
819                }
820            }
821
822            return null;
823        }
824
825        if (type instanceof TypeVariable<?>) {
826            for (final Type bound : getImplicitBounds((TypeVariable<?>) type)) {
827                // find the first bound that is assignable to the target class
828                if (isAssignable(bound, toClass)) {
829                    return getTypeArguments(bound, toClass, subtypeVarAssigns);
830                }
831            }
832
833            return null;
834        }
835        throw new IllegalStateException("found an unhandled type: " + type);
836    }
837
838    /**
839     * <p>Return a map of the type arguments of a parameterized type in the context of {@code toClass}.</p>
840     *
841     * @param parameterizedType the parameterized type
842     * @param toClass the class
843     * @param subtypeVarAssigns a map with type variables
844     * @return the {@code Map} with type arguments
845     */
846    private static Map<TypeVariable<?>, Type> getTypeArguments(
847            final ParameterizedType parameterizedType, final Class<?> toClass,
848            final Map<TypeVariable<?>, Type> subtypeVarAssigns) {
849        final Class<?> cls = getRawType(parameterizedType);
850
851        // make sure they're assignable
852        if (!isAssignable(cls, toClass)) {
853            return null;
854        }
855
856        final Type ownerType = parameterizedType.getOwnerType();
857        Map<TypeVariable<?>, Type> typeVarAssigns;
858
859        if (ownerType instanceof ParameterizedType) {
860            // get the owner type arguments first
861            final ParameterizedType parameterizedOwnerType = (ParameterizedType) ownerType;
862            typeVarAssigns = getTypeArguments(parameterizedOwnerType,
863                    getRawType(parameterizedOwnerType), subtypeVarAssigns);
864        } else {
865            // no owner, prep the type variable assignments map
866            typeVarAssigns = subtypeVarAssigns == null ? new HashMap<>()
867                    : new HashMap<>(subtypeVarAssigns);
868        }
869
870        // get the subject parameterized type's arguments
871        final Type[] typeArgs = parameterizedType.getActualTypeArguments();
872        // and get the corresponding type variables from the raw class
873        final TypeVariable<?>[] typeParams = cls.getTypeParameters();
874
875        // map the arguments to their respective type variables
876        for (int i = 0; i < typeParams.length; i++) {
877            final Type typeArg = typeArgs[i];
878            typeVarAssigns.put(typeParams[i], typeVarAssigns.containsKey(typeArg) ? typeVarAssigns
879                    .get(typeArg) : typeArg);
880        }
881
882        if (toClass.equals(cls)) {
883            // target class has been reached. Done.
884            return typeVarAssigns;
885        }
886
887        // walk the inheritance hierarchy until the target class is reached
888        return getTypeArguments(getClosestParentType(cls, toClass), toClass, typeVarAssigns);
889    }
890
891    /**
892     * <p>Return a map of the type arguments of a class in the context of {@code toClass}.</p>
893     *
894     * @param cls the class in question
895     * @param toClass the context class
896     * @param subtypeVarAssigns a map with type variables
897     * @return the {@code Map} with type arguments
898     */
899    private static Map<TypeVariable<?>, Type> getTypeArguments(Class<?> cls, final Class<?> toClass,
900            final Map<TypeVariable<?>, Type> subtypeVarAssigns) {
901        // make sure they're assignable
902        if (!isAssignable(cls, toClass)) {
903            return null;
904        }
905
906        // can't work with primitives
907        if (cls.isPrimitive()) {
908            // both classes are primitives?
909            if (toClass.isPrimitive()) {
910                // dealing with widening here. No type arguments to be
911                // harvested with these two types.
912                return new HashMap<>();
913            }
914
915            // work with wrapper the wrapper class instead of the primitive
916            cls = ClassUtils.primitiveToWrapper(cls);
917        }
918
919        // create a copy of the incoming map, or an empty one if it's null
920        final HashMap<TypeVariable<?>, Type> typeVarAssigns = subtypeVarAssigns == null ? new HashMap<>()
921                : new HashMap<>(subtypeVarAssigns);
922
923        // has target class been reached?
924        if (toClass.equals(cls)) {
925            return typeVarAssigns;
926        }
927
928        // walk the inheritance hierarchy until the target class is reached
929        return getTypeArguments(getClosestParentType(cls, toClass), toClass, typeVarAssigns);
930    }
931
932    /**
933     * <p>Tries to determine the type arguments of a class/interface based on a
934     * super parameterized type's type arguments. This method is the inverse of
935     * {@link #getTypeArguments(Type, Class)} which gets a class/interface's
936     * type arguments based on a subtype. It is far more limited in determining
937     * the type arguments for the subject class's type variables in that it can
938     * only determine those parameters that map from the subject {@link Class}
939     * object to the supertype.</p> <p>Example: {@link java.util.TreeSet
940     * TreeSet} sets its parameter as the parameter for
941     * {@link java.util.NavigableSet NavigableSet}, which in turn sets the
942     * parameter of {@link java.util.SortedSet}, which in turn sets the
943     * parameter of {@link Set}, which in turn sets the parameter of
944     * {@link java.util.Collection}, which in turn sets the parameter of
945     * {@link java.lang.Iterable}. Since {@code TreeSet}'s parameter maps
946     * (indirectly) to {@code Iterable}'s parameter, it will be able to
947     * determine that based on the super type {@code Iterable<? extends
948     * Map<Integer, ? extends Collection<?>>>}, the parameter of
949     * {@code TreeSet} is {@code ? extends Map<Integer, ? extends
950     * Collection<?>>}.</p>
951     *
952     * @param cls the class whose type parameters are to be determined, not {@code null}
953     * @param superType the super type from which {@code cls}'s type
954     * arguments are to be determined, not {@code null}
955     * @return a {@code Map} of the type assignments that could be determined
956     * for the type variables in each type in the inheritance hierarchy from
957     * {@code type} to {@code toClass} inclusive.
958     */
959    public static Map<TypeVariable<?>, Type> determineTypeArguments(final Class<?> cls,
960            final ParameterizedType superType) {
961        Validate.notNull(cls, "cls is null");
962        Validate.notNull(superType, "superType is null");
963
964        final Class<?> superClass = getRawType(superType);
965
966        // compatibility check
967        if (!isAssignable(cls, superClass)) {
968            return null;
969        }
970
971        if (cls.equals(superClass)) {
972            return getTypeArguments(superType, superClass, null);
973        }
974
975        // get the next class in the inheritance hierarchy
976        final Type midType = getClosestParentType(cls, superClass);
977
978        // can only be a class or a parameterized type
979        if (midType instanceof Class<?>) {
980            return determineTypeArguments((Class<?>) midType, superType);
981        }
982
983        final ParameterizedType midParameterizedType = (ParameterizedType) midType;
984        final Class<?> midClass = getRawType(midParameterizedType);
985        // get the type variables of the mid class that map to the type
986        // arguments of the super class
987        final Map<TypeVariable<?>, Type> typeVarAssigns = determineTypeArguments(midClass, superType);
988        // map the arguments of the mid type to the class type variables
989        mapTypeVariablesToArguments(cls, midParameterizedType, typeVarAssigns);
990
991        return typeVarAssigns;
992    }
993
994    /**
995     * <p>Performs a mapping of type variables.</p>
996     *
997     * @param <T> the generic type of the class in question
998     * @param cls the class in question
999     * @param parameterizedType the parameterized type
1000     * @param typeVarAssigns the map to be filled
1001     */
1002    private static <T> void mapTypeVariablesToArguments(final Class<T> cls,
1003            final ParameterizedType parameterizedType, final Map<TypeVariable<?>, Type> typeVarAssigns) {
1004        // capture the type variables from the owner type that have assignments
1005        final Type ownerType = parameterizedType.getOwnerType();
1006
1007        if (ownerType instanceof ParameterizedType) {
1008            // recursion to make sure the owner's owner type gets processed
1009            mapTypeVariablesToArguments(cls, (ParameterizedType) ownerType, typeVarAssigns);
1010        }
1011
1012        // parameterizedType is a generic interface/class (or it's in the owner
1013        // hierarchy of said interface/class) implemented/extended by the class
1014        // cls. Find out which type variables of cls are type arguments of
1015        // parameterizedType:
1016        final Type[] typeArgs = parameterizedType.getActualTypeArguments();
1017
1018        // of the cls's type variables that are arguments of parameterizedType,
1019        // find out which ones can be determined from the super type's arguments
1020        final TypeVariable<?>[] typeVars = getRawType(parameterizedType).getTypeParameters();
1021
1022        // use List view of type parameters of cls so the contains() method can be used:
1023        final List<TypeVariable<Class<T>>> typeVarList = Arrays.asList(cls
1024                .getTypeParameters());
1025
1026        for (int i = 0; i < typeArgs.length; i++) {
1027            final TypeVariable<?> typeVar = typeVars[i];
1028            final Type typeArg = typeArgs[i];
1029
1030            // argument of parameterizedType is a type variable of cls
1031            if (typeVarList.contains(typeArg)
1032            // type variable of parameterizedType has an assignment in
1033                    // the super type.
1034                    && typeVarAssigns.containsKey(typeVar)) {
1035                // map the assignment to the cls's type variable
1036                typeVarAssigns.put((TypeVariable<?>) typeArg, typeVarAssigns.get(typeVar));
1037            }
1038        }
1039    }
1040
1041    /**
1042     * <p>Get the closest parent type to the
1043     * super class specified by {@code superClass}.</p>
1044     *
1045     * @param cls the class in question
1046     * @param superClass the super class
1047     * @return the closes parent type
1048     */
1049    private static Type getClosestParentType(final Class<?> cls, final Class<?> superClass) {
1050        // only look at the interfaces if the super class is also an interface
1051        if (superClass.isInterface()) {
1052            // get the generic interfaces of the subject class
1053            final Type[] interfaceTypes = cls.getGenericInterfaces();
1054            // will hold the best generic interface match found
1055            Type genericInterface = null;
1056
1057            // find the interface closest to the super class
1058            for (final Type midType : interfaceTypes) {
1059                Class<?> midClass = null;
1060
1061                if (midType instanceof ParameterizedType) {
1062                    midClass = getRawType((ParameterizedType) midType);
1063                } else if (midType instanceof Class<?>) {
1064                    midClass = (Class<?>) midType;
1065                } else {
1066                    throw new IllegalStateException("Unexpected generic"
1067                            + " interface type found: " + midType);
1068                }
1069
1070                // check if this interface is further up the inheritance chain
1071                // than the previously found match
1072                if (isAssignable(midClass, superClass)
1073                        && isAssignable(genericInterface, (Type) midClass)) {
1074                    genericInterface = midType;
1075                }
1076            }
1077
1078            // found a match?
1079            if (genericInterface != null) {
1080                return genericInterface;
1081            }
1082        }
1083
1084        // none of the interfaces were descendants of the target class, so the
1085        // super class has to be one, instead
1086        return cls.getGenericSuperclass();
1087    }
1088
1089    /**
1090     * <p>Checks if the given value can be assigned to the target type
1091     * following the Java generics rules.</p>
1092     *
1093     * @param value the value to be checked
1094     * @param type the target type
1095     * @return {@code true} if {@code value} is an instance of {@code type}.
1096     */
1097    public static boolean isInstance(final Object value, final Type type) {
1098        if (type == null) {
1099            return false;
1100        }
1101
1102        return value == null ? !(type instanceof Class<?>) || !((Class<?>) type).isPrimitive()
1103                : isAssignable(value.getClass(), type, null);
1104    }
1105
1106    /**
1107     * <p>This method strips out the redundant upper bound types in type
1108     * variable types and wildcard types (or it would with wildcard types if
1109     * multiple upper bounds were allowed).</p> <p>Example, with the variable
1110     * type declaration:
1111     *
1112     * <pre>&lt;K extends java.util.Collection&lt;String&gt; &amp;
1113     * java.util.List&lt;String&gt;&gt;</pre>
1114     *
1115     * <p>
1116     * since {@code List} is a subinterface of {@code Collection},
1117     * this method will return the bounds as if the declaration had been:
1118     * </p>
1119     *
1120     * <pre>&lt;K extends java.util.List&lt;String&gt;&gt;</pre>
1121     *
1122     * @param bounds an array of types representing the upper bounds of either
1123     * {@link WildcardType} or {@link TypeVariable}, not {@code null}.
1124     * @return an array containing the values from {@code bounds} minus the
1125     * redundant types.
1126     */
1127    public static Type[] normalizeUpperBounds(final Type[] bounds) {
1128        Validate.notNull(bounds, "null value specified for bounds array");
1129        // don't bother if there's only one (or none) type
1130        if (bounds.length < 2) {
1131            return bounds;
1132        }
1133
1134        final Set<Type> types = new HashSet<>(bounds.length);
1135
1136        for (final Type type1 : bounds) {
1137            boolean subtypeFound = false;
1138
1139            for (final Type type2 : bounds) {
1140                if (type1 != type2 && isAssignable(type2, type1, null)) {
1141                    subtypeFound = true;
1142                    break;
1143                }
1144            }
1145
1146            if (!subtypeFound) {
1147                types.add(type1);
1148            }
1149        }
1150
1151        return types.toArray(ArrayUtils.EMPTY_TYPE_ARRAY);
1152    }
1153
1154    /**
1155     * <p>Returns an array containing the sole type of {@link Object} if
1156     * {@link TypeVariable#getBounds()} returns an empty array. Otherwise, it
1157     * returns the result of {@link TypeVariable#getBounds()} passed into
1158     * {@link #normalizeUpperBounds}.</p>
1159     *
1160     * @param typeVariable the subject type variable, not {@code null}
1161     * @return a non-empty array containing the bounds of the type variable.
1162     */
1163    public static Type[] getImplicitBounds(final TypeVariable<?> typeVariable) {
1164        Validate.notNull(typeVariable, "typeVariable is null");
1165        final Type[] bounds = typeVariable.getBounds();
1166
1167        return bounds.length == 0 ? new Type[] { Object.class } : normalizeUpperBounds(bounds);
1168    }
1169
1170    /**
1171     * <p>Returns an array containing the sole value of {@link Object} if
1172     * {@link WildcardType#getUpperBounds()} returns an empty array. Otherwise,
1173     * it returns the result of {@link WildcardType#getUpperBounds()}
1174     * passed into {@link #normalizeUpperBounds}.</p>
1175     *
1176     * @param wildcardType the subject wildcard type, not {@code null}
1177     * @return a non-empty array containing the upper bounds of the wildcard
1178     * type.
1179     */
1180    public static Type[] getImplicitUpperBounds(final WildcardType wildcardType) {
1181        Validate.notNull(wildcardType, "wildcardType is null");
1182        final Type[] bounds = wildcardType.getUpperBounds();
1183
1184        return bounds.length == 0 ? new Type[] { Object.class } : normalizeUpperBounds(bounds);
1185    }
1186
1187    /**
1188     * <p>Returns an array containing a single value of {@code null} if
1189     * {@link WildcardType#getLowerBounds()} returns an empty array. Otherwise,
1190     * it returns the result of {@link WildcardType#getLowerBounds()}.</p>
1191     *
1192     * @param wildcardType the subject wildcard type, not {@code null}
1193     * @return a non-empty array containing the lower bounds of the wildcard
1194     * type.
1195     */
1196    public static Type[] getImplicitLowerBounds(final WildcardType wildcardType) {
1197        Validate.notNull(wildcardType, "wildcardType is null");
1198        final Type[] bounds = wildcardType.getLowerBounds();
1199
1200        return bounds.length == 0 ? new Type[] { null } : bounds;
1201    }
1202
1203    /**
1204     * <p>Determines whether or not specified types satisfy the bounds of their
1205     * mapped type variables. When a type parameter extends another (such as
1206     * {@code <T, S extends T>}), uses another as a type parameter (such as
1207     * {@code <T, S extends Comparable>>}), or otherwise depends on
1208     * another type variable to be specified, the dependencies must be included
1209     * in {@code typeVarAssigns}.</p>
1210     *
1211     * @param typeVarAssigns specifies the potential types to be assigned to the
1212     * type variables, not {@code null}.
1213     * @return whether or not the types can be assigned to their respective type
1214     * variables.
1215     */
1216    public static boolean typesSatisfyVariables(final Map<TypeVariable<?>, Type> typeVarAssigns) {
1217        Validate.notNull(typeVarAssigns, "typeVarAssigns is null");
1218        // all types must be assignable to all the bounds of their mapped
1219        // type variable.
1220        for (final Map.Entry<TypeVariable<?>, Type> entry : typeVarAssigns.entrySet()) {
1221            final TypeVariable<?> typeVar = entry.getKey();
1222            final Type type = entry.getValue();
1223
1224            for (final Type bound : getImplicitBounds(typeVar)) {
1225                if (!isAssignable(type, substituteTypeVariables(bound, typeVarAssigns),
1226                        typeVarAssigns)) {
1227                    return false;
1228                }
1229            }
1230        }
1231        return true;
1232    }
1233
1234    /**
1235     * <p>Transforms the passed in type to a {@link Class} object. Type-checking method of convenience.</p>
1236     *
1237     * @param parameterizedType the type to be converted
1238     * @return the corresponding {@code Class} object
1239     * @throws IllegalStateException if the conversion fails
1240     */
1241    private static Class<?> getRawType(final ParameterizedType parameterizedType) {
1242        final Type rawType = parameterizedType.getRawType();
1243
1244        // check if raw type is a Class object
1245        // not currently necessary, but since the return type is Type instead of
1246        // Class, there's enough reason to believe that future versions of Java
1247        // may return other Type implementations. And type-safety checking is
1248        // rarely a bad idea.
1249        if (!(rawType instanceof Class<?>)) {
1250            throw new IllegalStateException("Wait... What!? Type of rawType: " + rawType);
1251        }
1252
1253        return (Class<?>) rawType;
1254    }
1255
1256    /**
1257     * <p>Get the raw type of a Java type, given its context. Primarily for use
1258     * with {@link TypeVariable}s and {@link GenericArrayType}s, or when you do
1259     * not know the runtime type of {@code type}: if you know you have a
1260     * {@link Class} instance, it is already raw; if you know you have a
1261     * {@link ParameterizedType}, its raw type is only a method call away.</p>
1262     *
1263     * @param type to resolve
1264     * @param assigningType type to be resolved against
1265     * @return the resolved {@link Class} object or {@code null} if
1266     * the type could not be resolved
1267     */
1268    public static Class<?> getRawType(final Type type, final Type assigningType) {
1269        if (type instanceof Class<?>) {
1270            // it is raw, no problem
1271            return (Class<?>) type;
1272        }
1273
1274        if (type instanceof ParameterizedType) {
1275            // simple enough to get the raw type of a ParameterizedType
1276            return getRawType((ParameterizedType) type);
1277        }
1278
1279        if (type instanceof TypeVariable<?>) {
1280            if (assigningType == null) {
1281                return null;
1282            }
1283
1284            // get the entity declaring this type variable
1285            final Object genericDeclaration = ((TypeVariable<?>) type).getGenericDeclaration();
1286
1287            // can't get the raw type of a method- or constructor-declared type
1288            // variable
1289            if (!(genericDeclaration instanceof Class<?>)) {
1290                return null;
1291            }
1292
1293            // get the type arguments for the declaring class/interface based
1294            // on the enclosing type
1295            final Map<TypeVariable<?>, Type> typeVarAssigns = getTypeArguments(assigningType,
1296                    (Class<?>) genericDeclaration);
1297
1298            // enclosingType has to be a subclass (or subinterface) of the
1299            // declaring type
1300            if (typeVarAssigns == null) {
1301                return null;
1302            }
1303
1304            // get the argument assigned to this type variable
1305            final Type typeArgument = typeVarAssigns.get(type);
1306
1307            if (typeArgument == null) {
1308                return null;
1309            }
1310
1311            // get the argument for this type variable
1312            return getRawType(typeArgument, assigningType);
1313        }
1314
1315        if (type instanceof GenericArrayType) {
1316            // get raw component type
1317            final Class<?> rawComponentType = getRawType(((GenericArrayType) type)
1318                    .getGenericComponentType(), assigningType);
1319
1320            // create array type from raw component type and return its class
1321            return Array.newInstance(rawComponentType, 0).getClass();
1322        }
1323
1324        // (hand-waving) this is not the method you're looking for
1325        if (type instanceof WildcardType) {
1326            return null;
1327        }
1328
1329        throw new IllegalArgumentException("unknown type: " + type);
1330    }
1331
1332    /**
1333     * Learn whether the specified type denotes an array type.
1334     * @param type the type to be checked
1335     * @return {@code true} if {@code type} is an array class or a {@link GenericArrayType}.
1336     */
1337    public static boolean isArrayType(final Type type) {
1338        return type instanceof GenericArrayType || type instanceof Class<?> && ((Class<?>) type).isArray();
1339    }
1340
1341    /**
1342     * Gets the array component type of {@code type}.
1343     * @param type the type to be checked
1344     * @return component type or null if type is not an array type
1345     */
1346    public static Type getArrayComponentType(final Type type) {
1347        if (type instanceof Class<?>) {
1348            final Class<?> cls = (Class<?>) type;
1349            return cls.isArray() ? cls.getComponentType() : null;
1350        }
1351        if (type instanceof GenericArrayType) {
1352            return ((GenericArrayType) type).getGenericComponentType();
1353        }
1354        return null;
1355    }
1356
1357    /**
1358     * Gets a type representing {@code type} with variable assignments "unrolled."
1359     *
1360     * @param typeArguments as from {@link TypeUtils#getTypeArguments(Type, Class)}
1361     * @param type the type to unroll variable assignments for
1362     * @return Type
1363     * @since 3.2
1364     */
1365    public static Type unrollVariables(Map<TypeVariable<?>, Type> typeArguments, final Type type) {
1366        if (typeArguments == null) {
1367            typeArguments = Collections.emptyMap();
1368        }
1369        if (containsTypeVariables(type)) {
1370            if (type instanceof TypeVariable<?>) {
1371                return unrollVariables(typeArguments, typeArguments.get(type));
1372            }
1373            if (type instanceof ParameterizedType) {
1374                final ParameterizedType p = (ParameterizedType) type;
1375                final Map<TypeVariable<?>, Type> parameterizedTypeArguments;
1376                if (p.getOwnerType() == null) {
1377                    parameterizedTypeArguments = typeArguments;
1378                } else {
1379                    parameterizedTypeArguments = new HashMap<>(typeArguments);
1380                    parameterizedTypeArguments.putAll(getTypeArguments(p));
1381                }
1382                final Type[] args = p.getActualTypeArguments();
1383                for (int i = 0; i < args.length; i++) {
1384                    final Type unrolled = unrollVariables(parameterizedTypeArguments, args[i]);
1385                    if (unrolled != null) {
1386                        args[i] = unrolled;
1387                    }
1388                }
1389                return parameterizeWithOwner(p.getOwnerType(), (Class<?>) p.getRawType(), args);
1390            }
1391            if (type instanceof WildcardType) {
1392                final WildcardType wild = (WildcardType) type;
1393                return wildcardType().withUpperBounds(unrollBounds(typeArguments, wild.getUpperBounds()))
1394                    .withLowerBounds(unrollBounds(typeArguments, wild.getLowerBounds())).build();
1395            }
1396        }
1397        return type;
1398    }
1399
1400    /**
1401     * Local helper method to unroll variables in a type bounds array.
1402     *
1403     * @param typeArguments assignments {@link Map}
1404     * @param bounds in which to expand variables
1405     * @return {@code bounds} with any variables reassigned
1406     * @since 3.2
1407     */
1408    private static Type[] unrollBounds(final Map<TypeVariable<?>, Type> typeArguments, final Type[] bounds) {
1409        Type[] result = bounds;
1410        int i = 0;
1411        for (; i < result.length; i++) {
1412            final Type unrolled = unrollVariables(typeArguments, result[i]);
1413            if (unrolled == null) {
1414                result = ArrayUtils.remove(result, i--);
1415            } else {
1416                result[i] = unrolled;
1417            }
1418        }
1419        return result;
1420    }
1421
1422    /**
1423     * Learn, recursively, whether any of the type parameters associated with {@code type} are bound to variables.
1424     *
1425     * @param type the type to check for type variables
1426     * @return boolean
1427     * @since 3.2
1428     */
1429    public static boolean containsTypeVariables(final Type type) {
1430        if (type instanceof TypeVariable<?>) {
1431            return true;
1432        }
1433        if (type instanceof Class<?>) {
1434            return ((Class<?>) type).getTypeParameters().length > 0;
1435        }
1436        if (type instanceof ParameterizedType) {
1437            for (final Type arg : ((ParameterizedType) type).getActualTypeArguments()) {
1438                if (containsTypeVariables(arg)) {
1439                    return true;
1440                }
1441            }
1442            return false;
1443        }
1444        if (type instanceof WildcardType) {
1445            final WildcardType wild = (WildcardType) type;
1446            return containsTypeVariables(getImplicitLowerBounds(wild)[0])
1447                || containsTypeVariables(getImplicitUpperBounds(wild)[0]);
1448        }
1449        return false;
1450    }
1451
1452    /**
1453     * Create a parameterized type instance.
1454     *
1455     * @param rawClass the raw class to create a parameterized type instance for
1456     * @param typeArguments the types used for parameterization
1457     * @return {@link ParameterizedType}
1458     * @since 3.2
1459     */
1460    public static final ParameterizedType parameterize(final Class<?> rawClass, final Type... typeArguments) {
1461        return parameterizeWithOwner(null, rawClass, typeArguments);
1462    }
1463
1464    /**
1465     * Create a parameterized type instance.
1466     *
1467     * @param rawClass the raw class to create a parameterized type instance for
1468     * @param typeArgMappings the mapping used for parameterization
1469     * @return {@link ParameterizedType}
1470     * @since 3.2
1471     */
1472    public static final ParameterizedType parameterize(final Class<?> rawClass,
1473        final Map<TypeVariable<?>, Type> typeArgMappings) {
1474        Validate.notNull(rawClass, "raw class is null");
1475        Validate.notNull(typeArgMappings, "typeArgMappings is null");
1476        return parameterizeWithOwner(null, rawClass,
1477            extractTypeArgumentsFrom(typeArgMappings, rawClass.getTypeParameters()));
1478    }
1479
1480    /**
1481     * Create a parameterized type instance.
1482     *
1483     * @param owner the owning type
1484     * @param rawClass the raw class to create a parameterized type instance for
1485     * @param typeArguments the types used for parameterization
1486     *
1487     * @return {@link ParameterizedType}
1488     * @since 3.2
1489     */
1490    public static final ParameterizedType parameterizeWithOwner(final Type owner, final Class<?> rawClass,
1491        final Type... typeArguments) {
1492        Validate.notNull(rawClass, "raw class is null");
1493        final Type useOwner;
1494        if (rawClass.getEnclosingClass() == null) {
1495            Validate.isTrue(owner == null, "no owner allowed for top-level %s", rawClass);
1496            useOwner = null;
1497        } else if (owner == null) {
1498            useOwner = rawClass.getEnclosingClass();
1499        } else {
1500            Validate.isTrue(isAssignable(owner, rawClass.getEnclosingClass()),
1501                "%s is invalid owner type for parameterized %s", owner, rawClass);
1502            useOwner = owner;
1503        }
1504        Validate.noNullElements(typeArguments, "null type argument at index %s");
1505        Validate.isTrue(rawClass.getTypeParameters().length == typeArguments.length,
1506            "invalid number of type parameters specified: expected %d, got %d", rawClass.getTypeParameters().length,
1507            typeArguments.length);
1508
1509        return new ParameterizedTypeImpl(rawClass, useOwner, typeArguments);
1510    }
1511
1512    /**
1513     * Create a parameterized type instance.
1514     *
1515     * @param owner the owning type
1516     * @param rawClass the raw class to create a parameterized type instance for
1517     * @param typeArgMappings the mapping used for parameterization
1518     * @return {@link ParameterizedType}
1519     * @since 3.2
1520     */
1521    public static final ParameterizedType parameterizeWithOwner(final Type owner, final Class<?> rawClass,
1522        final Map<TypeVariable<?>, Type> typeArgMappings) {
1523        Validate.notNull(rawClass, "raw class is null");
1524        Validate.notNull(typeArgMappings, "typeArgMappings is null");
1525        return parameterizeWithOwner(owner, rawClass,
1526            extractTypeArgumentsFrom(typeArgMappings, rawClass.getTypeParameters()));
1527    }
1528
1529    /**
1530     * Helper method to establish the formal parameters for a parameterized type.
1531     * @param mappings map containing the assignments
1532     * @param variables expected map keys
1533     * @return array of map values corresponding to specified keys
1534     */
1535    private static Type[] extractTypeArgumentsFrom(final Map<TypeVariable<?>, Type> mappings, final TypeVariable<?>[] variables) {
1536        final Type[] result = new Type[variables.length];
1537        int index = 0;
1538        for (final TypeVariable<?> var : variables) {
1539            Validate.isTrue(mappings.containsKey(var), "missing argument mapping for %s", toString(var));
1540            result[index++] = mappings.get(var);
1541        }
1542        return result;
1543    }
1544
1545    /**
1546     * Gets a {@link WildcardTypeBuilder}.
1547     * @return {@link WildcardTypeBuilder}
1548     * @since 3.2
1549     */
1550    public static WildcardTypeBuilder wildcardType() {
1551        return new WildcardTypeBuilder();
1552    }
1553
1554    /**
1555     * Create a generic array type instance.
1556     *
1557     * @param componentType the type of the elements of the array. For example the component type of {@code boolean[]}
1558     *                      is {@code boolean}
1559     * @return {@link GenericArrayType}
1560     * @since 3.2
1561     */
1562    public static GenericArrayType genericArrayType(final Type componentType) {
1563        return new GenericArrayTypeImpl(Validate.notNull(componentType, "componentType is null"));
1564    }
1565
1566    /**
1567     * Check equality of types.
1568     *
1569     * @param type1 the first type
1570     * @param type2 the second type
1571     * @return boolean
1572     * @since 3.2
1573     */
1574    public static boolean equals(final Type type1, final Type type2) {
1575        if (Objects.equals(type1, type2)) {
1576            return true;
1577        }
1578        if (type1 instanceof ParameterizedType) {
1579            return equals((ParameterizedType) type1, type2);
1580        }
1581        if (type1 instanceof GenericArrayType) {
1582            return equals((GenericArrayType) type1, type2);
1583        }
1584        if (type1 instanceof WildcardType) {
1585            return equals((WildcardType) type1, type2);
1586        }
1587        return false;
1588    }
1589
1590    /**
1591     * Learn whether {@code t} equals {@code p}.
1592     * @param parameterizedType LHS
1593     * @param type RHS
1594     * @return boolean
1595     * @since 3.2
1596     */
1597    private static boolean equals(final ParameterizedType parameterizedType, final Type type) {
1598        if (type instanceof ParameterizedType) {
1599            final ParameterizedType other = (ParameterizedType) type;
1600            if (equals(parameterizedType.getRawType(), other.getRawType())
1601                && equals(parameterizedType.getOwnerType(), other.getOwnerType())) {
1602                return equals(parameterizedType.getActualTypeArguments(), other.getActualTypeArguments());
1603            }
1604        }
1605        return false;
1606    }
1607
1608    /**
1609     * Learn whether {@code t} equals {@code a}.
1610     * @param genericArrayType LHS
1611     * @param type RHS
1612     * @return boolean
1613     * @since 3.2
1614     */
1615    private static boolean equals(final GenericArrayType genericArrayType, final Type type) {
1616        return type instanceof GenericArrayType
1617            && equals(genericArrayType.getGenericComponentType(), ((GenericArrayType) type).getGenericComponentType());
1618    }
1619
1620    /**
1621     * Learn whether {@code t} equals {@code w}.
1622     * @param wildcardType LHS
1623     * @param type RHS
1624     * @return boolean
1625     * @since 3.2
1626     */
1627    private static boolean equals(final WildcardType wildcardType, final Type type) {
1628        if (type instanceof WildcardType) {
1629            final WildcardType other = (WildcardType) type;
1630            return equals(getImplicitLowerBounds(wildcardType), getImplicitLowerBounds(other))
1631                && equals(getImplicitUpperBounds(wildcardType), getImplicitUpperBounds(other));
1632        }
1633        return false;
1634    }
1635
1636    /**
1637     * Learn whether {@code t1} equals {@code t2}.
1638     * @param type1 LHS
1639     * @param type2 RHS
1640     * @return boolean
1641     * @since 3.2
1642     */
1643    private static boolean equals(final Type[] type1, final Type[] type2) {
1644        if (type1.length == type2.length) {
1645            for (int i = 0; i < type1.length; i++) {
1646                if (!equals(type1[i], type2[i])) {
1647                    return false;
1648                }
1649            }
1650            return true;
1651        }
1652        return false;
1653    }
1654
1655    /**
1656     * Present a given type as a Java-esque String.
1657     *
1658     * @param type the type to create a String representation for, not {@code null}
1659     * @return String
1660     * @since 3.2
1661     */
1662    public static String toString(final Type type) {
1663        Validate.notNull(type);
1664        if (type instanceof Class<?>) {
1665            return classToString((Class<?>) type);
1666        }
1667        if (type instanceof ParameterizedType) {
1668            return parameterizedTypeToString((ParameterizedType) type);
1669        }
1670        if (type instanceof WildcardType) {
1671            return wildcardTypeToString((WildcardType) type);
1672        }
1673        if (type instanceof TypeVariable<?>) {
1674            return typeVariableToString((TypeVariable<?>) type);
1675        }
1676        if (type instanceof GenericArrayType) {
1677            return genericArrayTypeToString((GenericArrayType) type);
1678        }
1679        throw new IllegalArgumentException(ObjectUtils.identityToString(type));
1680    }
1681
1682    /**
1683     * Format a {@link TypeVariable} including its {@link GenericDeclaration}.
1684     *
1685     * @param var the type variable to create a String representation for, not {@code null}
1686     * @return String
1687     * @since 3.2
1688     */
1689    public static String toLongString(final TypeVariable<?> var) {
1690        Validate.notNull(var, "var is null");
1691        final StringBuilder buf = new StringBuilder();
1692        final GenericDeclaration d = var.getGenericDeclaration();
1693        if (d instanceof Class<?>) {
1694            Class<?> c = (Class<?>) d;
1695            while (true) {
1696                if (c.getEnclosingClass() == null) {
1697                    buf.insert(0, c.getName());
1698                    break;
1699                }
1700                buf.insert(0, c.getSimpleName()).insert(0, '.');
1701                c = c.getEnclosingClass();
1702            }
1703        } else if (d instanceof Type) {// not possible as of now
1704            buf.append(toString((Type) d));
1705        } else {
1706            buf.append(d);
1707        }
1708        return buf.append(':').append(typeVariableToString(var)).toString();
1709    }
1710
1711    /**
1712     * Wrap the specified {@link Type} in a {@link Typed} wrapper.
1713     *
1714     * @param <T> inferred generic type
1715     * @param type to wrap
1716     * @return Typed&lt;T&gt;
1717     * @since 3.2
1718     */
1719    public static <T> Typed<T> wrap(final Type type) {
1720        return () -> type;
1721    }
1722
1723    /**
1724     * Wrap the specified {@link Class} in a {@link Typed} wrapper.
1725     *
1726     * @param <T> generic type
1727     * @param type to wrap
1728     * @return Typed&lt;T&gt;
1729     * @since 3.2
1730     */
1731    public static <T> Typed<T> wrap(final Class<T> type) {
1732        return wrap((Type) type);
1733    }
1734
1735    /**
1736     * Format a {@link Class} as a {@link String}.
1737     * @param cls {@code Class} to format
1738     * @return String
1739     * @since 3.2
1740     */
1741    private static String classToString(final Class<?> cls) {
1742        if (cls.isArray()) {
1743            return toString(cls.getComponentType()) + "[]";
1744        }
1745
1746        final StringBuilder buf = new StringBuilder();
1747
1748        if (cls.getEnclosingClass() != null) {
1749            buf.append(classToString(cls.getEnclosingClass())).append('.').append(cls.getSimpleName());
1750        } else {
1751            buf.append(cls.getName());
1752        }
1753        if (cls.getTypeParameters().length > 0) {
1754            buf.append('<');
1755            appendAllTo(buf, ", ", cls.getTypeParameters());
1756            buf.append('>');
1757        }
1758        return buf.toString();
1759    }
1760
1761    /**
1762     * Format a {@link TypeVariable} as a {@link String}.
1763     * @param typeVariable {@code TypeVariable} to format
1764     * @return String
1765     * @since 3.2
1766     */
1767    private static String typeVariableToString(final TypeVariable<?> typeVariable) {
1768        final StringBuilder buf = new StringBuilder(typeVariable.getName());
1769        final Type[] bounds = typeVariable.getBounds();
1770        if (bounds.length > 0 && !(bounds.length == 1 && Object.class.equals(bounds[0]))) {
1771            buf.append(" extends ");
1772            appendAllTo(buf, " & ", typeVariable.getBounds());
1773        }
1774        return buf.toString();
1775    }
1776
1777    /**
1778     * Format a {@link ParameterizedType} as a {@link String}.
1779     * @param parameterizedType {@code ParameterizedType} to format
1780     * @return String
1781     * @since 3.2
1782     */
1783    private static String parameterizedTypeToString(final ParameterizedType parameterizedType) {
1784        final StringBuilder builder = new StringBuilder();
1785
1786        final Type useOwner = parameterizedType.getOwnerType();
1787        final Class<?> raw = (Class<?>) parameterizedType.getRawType();
1788
1789        if (useOwner == null) {
1790            builder.append(raw.getName());
1791        } else {
1792            if (useOwner instanceof Class<?>) {
1793                builder.append(((Class<?>) useOwner).getName());
1794            } else {
1795                builder.append(useOwner.toString());
1796            }
1797            builder.append('.').append(raw.getSimpleName());
1798        }
1799
1800        final int[] recursiveTypeIndexes = findRecursiveTypes(parameterizedType);
1801
1802        if (recursiveTypeIndexes.length > 0) {
1803            appendRecursiveTypes(builder, recursiveTypeIndexes, parameterizedType.getActualTypeArguments());
1804        } else {
1805            appendAllTo(builder.append('<'), ", ", parameterizedType.getActualTypeArguments()).append('>');
1806        }
1807
1808        return builder.toString();
1809    }
1810
1811    private static void appendRecursiveTypes(final StringBuilder builder, final int[] recursiveTypeIndexes,
1812        final Type[] argumentTypes) {
1813        for (int i = 0; i < recursiveTypeIndexes.length; i++) {
1814            appendAllTo(builder.append('<'), ", ", argumentTypes[i].toString()).append('>');
1815        }
1816
1817        final Type[] argumentsFiltered = ArrayUtils.removeAll(argumentTypes, recursiveTypeIndexes);
1818
1819        if (argumentsFiltered.length > 0) {
1820            appendAllTo(builder.append('<'), ", ", argumentsFiltered).append('>');
1821        }
1822    }
1823
1824    private static int[] findRecursiveTypes(final ParameterizedType parameterizedType) {
1825        final Type[] filteredArgumentTypes = Arrays.copyOf(parameterizedType.getActualTypeArguments(),
1826            parameterizedType.getActualTypeArguments().length);
1827        int[] indexesToRemove = {};
1828        for (int i = 0; i < filteredArgumentTypes.length; i++) {
1829            if (filteredArgumentTypes[i] instanceof TypeVariable<?>) {
1830                if (containsVariableTypeSameParametrizedTypeBound(((TypeVariable<?>) filteredArgumentTypes[i]),
1831                    parameterizedType)) {
1832                    indexesToRemove = ArrayUtils.add(indexesToRemove, i);
1833                }
1834            }
1835        }
1836        return indexesToRemove;
1837    }
1838
1839    private static boolean containsVariableTypeSameParametrizedTypeBound(final TypeVariable<?> typeVariable,
1840        final ParameterizedType parameterizedType) {
1841        return ArrayUtils.contains(typeVariable.getBounds(), parameterizedType);
1842    }
1843
1844    /**
1845     * Format a {@link WildcardType} as a {@link String}.
1846     * @param wildcardType {@code WildcardType} to format
1847     * @return String
1848     * @since 3.2
1849     */
1850    private static String wildcardTypeToString(final WildcardType wildcardType) {
1851        final StringBuilder buf = new StringBuilder().append('?');
1852        final Type[] lowerBounds = wildcardType.getLowerBounds();
1853        final Type[] upperBounds = wildcardType.getUpperBounds();
1854        if (lowerBounds.length > 1 || lowerBounds.length == 1 && lowerBounds[0] != null) {
1855            appendAllTo(buf.append(" super "), " & ", lowerBounds);
1856        } else if (upperBounds.length > 1 || upperBounds.length == 1 && !Object.class.equals(upperBounds[0])) {
1857            appendAllTo(buf.append(" extends "), " & ", upperBounds);
1858        }
1859        return buf.toString();
1860    }
1861
1862    /**
1863     * Format a {@link GenericArrayType} as a {@link String}.
1864     * @param genericArrayType {@code GenericArrayType} to format
1865     * @return String
1866     * @since 3.2
1867     */
1868    private static String genericArrayTypeToString(final GenericArrayType genericArrayType) {
1869        return String.format("%s[]", toString(genericArrayType.getGenericComponentType()));
1870    }
1871
1872    /**
1873     * Append {@code types} to {@code builder} with separator {@code sep}.
1874     * @param builder destination
1875     * @param sep separator
1876     * @param types to append
1877     * @return {@code builder}
1878     * @since 3.2
1879     */
1880    private static <T> StringBuilder appendAllTo(final StringBuilder builder, final String sep,
1881        @SuppressWarnings("unchecked") final T... types) {
1882        Validate.notEmpty(Validate.noNullElements(types));
1883        if (types.length > 0) {
1884            builder.append(toString(types[0]));
1885            for (int i = 1; i < types.length; i++) {
1886                builder.append(sep).append(toString(types[i]));
1887            }
1888        }
1889        return builder;
1890    }
1891
1892    private static <T> String toString(final T object) {
1893        return object instanceof Type ? toString((Type) object) : object.toString();
1894    }
1895
1896}