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