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