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