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