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