    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     */
    017    package org.apache.commons.lang3;
    018
    019    import java.lang.reflect.Method;
    020    import java.lang.reflect.Modifier;
    021    import java.util.ArrayList;
    022    import java.util.HashMap;
    023    import java.util.HashSet;
    024    import java.util.LinkedHashSet;
    025    import java.util.List;
    026    import java.util.Map;
    027
    028
    029    /**
    030     * <p>Operates on classes without using reflection.</p>
    031     *
    032     * <p>This class handles invalid {@code null} inputs as best it can.
    033     * Each method documents its behaviour in more detail.</p>
    034     *
    035     * <p>The notion of a {@code canonical name} includes the human
    036     * readable name for the type, for example {@code int[]}. The
    037     * non-canonical method variants work with the JVM names, such as
    038     * {@code [I}. </p>
    039     *
    040     * @since 2.0
    041     * @version $Id: ClassUtils.java 1199894 2011-11-09 17:53:59Z ggregory $
    042     */
    043    public class ClassUtils {
    044
    045        /**
    046         * <p>The package separator character: <code>'&#x2e;' == {@value}</code>.</p>
    047         */
    048        public static final char PACKAGE_SEPARATOR_CHAR = '.';
    049
    050        /**
    051         * <p>The package separator String: {@code "&#x2e;"}.</p>
    052         */
    053        public static final String PACKAGE_SEPARATOR = String.valueOf(PACKAGE_SEPARATOR_CHAR);
    054
    055        /**
    056         * <p>The inner class separator character: <code>'$' == {@value}</code>.</p>
    057         */
    058        public static final char INNER_CLASS_SEPARATOR_CHAR = '$';
    059
    060        /**
    061         * <p>The inner class separator String: {@code "$"}.</p>
    062         */
    063        public static final String INNER_CLASS_SEPARATOR = String.valueOf(INNER_CLASS_SEPARATOR_CHAR);
    064
    065        /**
    066         * Maps primitive {@code Class}es to their corresponding wrapper {@code Class}.
    067         */
    068        private static final Map<Class<?>, Class<?>> primitiveWrapperMap = new HashMap<Class<?>, Class<?>>();
    069        static {
    070             primitiveWrapperMap.put(Boolean.TYPE, Boolean.class);
    071             primitiveWrapperMap.put(Byte.TYPE, Byte.class);
    072             primitiveWrapperMap.put(Character.TYPE, Character.class);
    073             primitiveWrapperMap.put(Short.TYPE, Short.class);
    074             primitiveWrapperMap.put(Integer.TYPE, Integer.class);
    075             primitiveWrapperMap.put(Long.TYPE, Long.class);
    076             primitiveWrapperMap.put(Double.TYPE, Double.class);
    077             primitiveWrapperMap.put(Float.TYPE, Float.class);
    078             primitiveWrapperMap.put(Void.TYPE, Void.TYPE);
    079        }
    080
    081        /**
    082         * Maps wrapper {@code Class}es to their corresponding primitive types.
    083         */
    084        private static final Map<Class<?>, Class<?>> wrapperPrimitiveMap = new HashMap<Class<?>, Class<?>>();
    085        static {
    086            for (Class<?> primitiveClass : primitiveWrapperMap.keySet()) {
    087                Class<?> wrapperClass = primitiveWrapperMap.get(primitiveClass);
    088                if (!primitiveClass.equals(wrapperClass)) {
    089                    wrapperPrimitiveMap.put(wrapperClass, primitiveClass);
    090                }
    091            }
    092        }
    093
    094        /**
    095         * Maps a primitive class name to its corresponding abbreviation used in array class names.
    096         */
    097        private static final Map<String, String> abbreviationMap = new HashMap<String, String>();
    098
    099        /**
    100         * Maps an abbreviation used in array class names to corresponding primitive class name.
    101         */
    102        private static final Map<String, String> reverseAbbreviationMap = new HashMap<String, String>();
    103
    104        /**
    105         * Add primitive type abbreviation to maps of abbreviations.
    106         *
    107         * @param primitive Canonical name of primitive type
    108         * @param abbreviation Corresponding abbreviation of primitive type
    109         */
    110        private static void addAbbreviation(String primitive, String abbreviation) {
    111            abbreviationMap.put(primitive, abbreviation);
    112            reverseAbbreviationMap.put(abbreviation, primitive);
    113        }
    114
    115        /**
    116         * Feed abbreviation maps
    117         */
    118        static {
    119            addAbbreviation("int", "I");
    120            addAbbreviation("boolean", "Z");
    121            addAbbreviation("float", "F");
    122            addAbbreviation("long", "J");
    123            addAbbreviation("short", "S");
    124            addAbbreviation("byte", "B");
    125            addAbbreviation("double", "D");
    126            addAbbreviation("char", "C");
    127        }
    128
    129        /**
    130         * <p>ClassUtils instances should NOT be constructed in standard programming.
    131         * Instead, the class should be used as
    132         * {@code ClassUtils.getShortClassName(cls)}.</p>
    133         *
    134         * <p>This constructor is public to permit tools that require a JavaBean
    135         * instance to operate.</p>
    136         */
    137        public ClassUtils() {
    138          super();
    139        }
    140
    141        // Short class name
    142        // ----------------------------------------------------------------------
    143        /**
    144         * <p>Gets the class name minus the package name for an {@code Object}.</p>
    145         *
    146         * @param object  the class to get the short name for, may be null
    147         * @param valueIfNull  the value to return if null
    148         * @return the class name of the object without the package name, or the null value
    149         */
    150        public static String getShortClassName(Object object, String valueIfNull) {
    151            if (object == null) {
    152                return valueIfNull;
    153            }
    154            return getShortClassName(object.getClass());
    155        }
    156
    157        /**
    158         * <p>Gets the class name minus the package name from a {@code Class}.</p>
    159         *
    160         * <p>Consider using the Java 5 API {@link Class#getSimpleName()} instead.
    161         * The one known difference is that this code will return {@code "Map.Entry"} while
    162         * the {@code java.lang.Class} variant will simply return {@code "Entry"}. </p>
    163         *
    164         * @param cls  the class to get the short name for.
    165         * @return the class name without the package name or an empty string
    166         */
    167        public static String getShortClassName(Class<?> cls) {
    168            if (cls == null) {
    169                return StringUtils.EMPTY;
    170            }
    171            return getShortClassName(cls.getName());
    172        }
    173
    174        /**
    175         * <p>Gets the class name minus the package name from a String.</p>
    176         *
    177         * <p>The string passed in is assumed to be a class name - it is not checked.</p>
    178
    179         * <p>Note that this method differs from Class.getSimpleName() in that this will
    180         * return {@code "Map.Entry"} whilst the {@code java.lang.Class} variant will simply
    181         * return {@code "Entry"}. </p>
    182         *
    183         * @param className  the className to get the short name for
    184         * @return the class name of the class without the package name or an empty string
    185         */
    186        public static String getShortClassName(String className) {
    187            if (className == null) {
    188                return StringUtils.EMPTY;
    189            }
    190            if (className.length() == 0) {
    191                return StringUtils.EMPTY;
    192            }
    193
    194            StringBuilder arrayPrefix = new StringBuilder();
    195
    196            // Handle array encoding
    197            if (className.startsWith("[")) {
    198                while (className.charAt(0) == '[') {
    199                    className = className.substring(1);
    200                    arrayPrefix.append("[]");
    201                }
    202                // Strip Object type encoding
    203                if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';') {
    204                    className = className.substring(1, className.length() - 1);
    205                }
    206            }
    207
    208            if (reverseAbbreviationMap.containsKey(className)) {
    209                className = reverseAbbreviationMap.get(className);
    210            }
    211
    212            int lastDotIdx = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR);
    213            int innerIdx = className.indexOf(
    214                    INNER_CLASS_SEPARATOR_CHAR, lastDotIdx == -1 ? 0 : lastDotIdx + 1);
    215            String out = className.substring(lastDotIdx + 1);
    216            if (innerIdx != -1) {
    217                out = out.replace(INNER_CLASS_SEPARATOR_CHAR, PACKAGE_SEPARATOR_CHAR);
    218            }
    219            return out + arrayPrefix;
    220        }
    221
    222        /**
    223         * <p>Null-safe version of <code>aClass.getSimpleName()</code></p>
    224         *
    225         * @param cls the class for which to get the simple name.
    226         * @return the simple class name.
    227         * @since 3.0
    228         * @see Class#getSimpleName()
    229         */
    230        public static String getSimpleName(Class<?> cls) {
    231            if (cls == null) {
    232                return StringUtils.EMPTY;
    233            }
    234            return cls.getSimpleName();
    235        }
    236
    237        /**
    238         * <p>Null-safe version of <code>aClass.getSimpleName()</code></p>
    239         *
    240         * @param object the object for which to get the simple class name.
    241         * @param valueIfNull the value to return if <code>object</code> is <code>null</code>
    242         * @return the simple class name.
    243         * @since 3.0
    244         * @see Class#getSimpleName()
    245         */
    246        public static String getSimpleName(Object object, String valueIfNull) {
    247            if (object == null) {
    248                return valueIfNull;
    249            }
    250            return getSimpleName(object.getClass());
    251        }
    252
    253        // Package name
    254        // ----------------------------------------------------------------------
    255        /**
    256         * <p>Gets the package name of an {@code Object}.</p>
    257         *
    258         * @param object  the class to get the package name for, may be null
    259         * @param valueIfNull  the value to return if null
    260         * @return the package name of the object, or the null value
    261         */
    262        public static String getPackageName(Object object, String valueIfNull) {
    263            if (object == null) {
    264                return valueIfNull;
    265            }
    266            return getPackageName(object.getClass());
    267        }
    268
    269        /**
    270         * <p>Gets the package name of a {@code Class}.</p>
    271         *
    272         * @param cls  the class to get the package name for, may be {@code null}.
    273         * @return the package name or an empty string
    274         */
    275        public static String getPackageName(Class<?> cls) {
    276            if (cls == null) {
    277                return StringUtils.EMPTY;
    278            }
    279            return getPackageName(cls.getName());
    280        }
    281
    282        /**
    283         * <p>Gets the package name from a {@code String}.</p>
    284         *
    285         * <p>The string passed in is assumed to be a class name - it is not checked.</p>
    286         * <p>If the class is unpackaged, return an empty string.</p>
    287         *
    288         * @param className  the className to get the package name for, may be {@code null}
    289         * @return the package name or an empty string
    290         */
    291        public static String getPackageName(String className) {
    292            if (className == null || className.length() == 0) {
    293                return StringUtils.EMPTY;
    294            }
    295
    296            // Strip array encoding
    297            while (className.charAt(0) == '[') {
    298                className = className.substring(1);
    299            }
    300            // Strip Object type encoding
    301            if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';') {
    302                className = className.substring(1);
    303            }
    304
    305            int i = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR);
    306            if (i == -1) {
    307                return StringUtils.EMPTY;
    308            }
    309            return className.substring(0, i);
    310        }
    311
    312        // Superclasses/Superinterfaces
    313        // ----------------------------------------------------------------------
    314        /**
    315         * <p>Gets a {@code List} of superclasses for the given class.</p>
    316         *
    317         * @param cls  the class to look up, may be {@code null}
    318         * @return the {@code List} of superclasses in order going up from this one
    319         *  {@code null} if null input
    320         */
    321        public static List<Class<?>> getAllSuperclasses(Class<?> cls) {
    322            if (cls == null) {
    323                return null;
    324            }
    325            List<Class<?>> classes = new ArrayList<Class<?>>();
    326            Class<?> superclass = cls.getSuperclass();
    327            while (superclass != null) {
    328                classes.add(superclass);
    329                superclass = superclass.getSuperclass();
    330            }
    331            return classes;
    332        }
    333
    334        /**
    335         * <p>Gets a {@code List} of all interfaces implemented by the given
    336         * class and its superclasses.</p>
    337         *
    338         * <p>The order is determined by looking through each interface in turn as
    339         * declared in the source file and following its hierarchy up. Then each
    340         * superclass is considered in the same way. Later duplicates are ignored,
    341         * so the order is maintained.</p>
    342         *
    343         * @param cls  the class to look up, may be {@code null}
    344         * @return the {@code List} of interfaces in order,
    345         *  {@code null} if null input
    346         */
    347        public static List<Class<?>> getAllInterfaces(Class<?> cls) {
    348            if (cls == null) {
    349                return null;
    350            }
    351
    352            LinkedHashSet<Class<?>> interfacesFound = new LinkedHashSet<Class<?>>();
    353            getAllInterfaces(cls, interfacesFound);
    354
    355            return new ArrayList<Class<?>>(interfacesFound);
    356        }
    357
    358        /**
    359         * Get the interfaces for the specified class.
    360         *
    361         * @param cls  the class to look up, may be {@code null}
    362         * @param interfacesFound the {@code Set} of interfaces for the class
    363         */
    364        private static void getAllInterfaces(Class<?> cls, HashSet<Class<?>> interfacesFound) {
    365            while (cls != null) {
    366                Class<?>[] interfaces = cls.getInterfaces();
    367
    368                for (Class<?> i : interfaces) {
    369                    if (interfacesFound.add(i)) {
    370                        getAllInterfaces(i, interfacesFound);
    371                    }
    372                }
    373
    374                cls = cls.getSuperclass();
    375             }
    376         }
    377
    378        // Convert list
    379        // ----------------------------------------------------------------------
    380        /**
    381         * <p>Given a {@code List} of class names, this method converts them into classes.</p>
    382         *
    383         * <p>A new {@code List} is returned. If the class name cannot be found, {@code null}
    384         * is stored in the {@code List}. If the class name in the {@code List} is
    385         * {@code null}, {@code null} is stored in the output {@code List}.</p>
    386         *
    387         * @param classNames  the classNames to change
    388         * @return a {@code List} of Class objects corresponding to the class names,
    389         *  {@code null} if null input
    390         * @throws ClassCastException if classNames contains a non String entry
    391         */
    392        public static List<Class<?>> convertClassNamesToClasses(List<String> classNames) {
    393            if (classNames == null) {
    394                return null;
    395            }
    396            List<Class<?>> classes = new ArrayList<Class<?>>(classNames.size());
    397            for (String className : classNames) {
    398                try {
    399                    classes.add(Class.forName(className));
    400                } catch (Exception ex) {
    401                    classes.add(null);
    402                }
    403            }
    404            return classes;
    405        }
    406
    407        /**
    408         * <p>Given a {@code List} of {@code Class} objects, this method converts
    409         * them into class names.</p>
    410         *
    411         * <p>A new {@code List} is returned. {@code null} objects will be copied into
    412         * the returned list as {@code null}.</p>
    413         *
    414         * @param classes  the classes to change
    415         * @return a {@code List} of class names corresponding to the Class objects,
    416         *  {@code null} if null input
    417         * @throws ClassCastException if {@code classes} contains a non-{@code Class} entry
    418         */
    419        public static List<String> convertClassesToClassNames(List<Class<?>> classes) {
    420            if (classes == null) {
    421                return null;
    422            }
    423            List<String> classNames = new ArrayList<String>(classes.size());
    424            for (Class<?> cls : classes) {
    425                if (cls == null) {
    426                    classNames.add(null);
    427                } else {
    428                    classNames.add(cls.getName());
    429                }
    430            }
    431            return classNames;
    432        }
    433
    434        // Is assignable
    435        // ----------------------------------------------------------------------
    436        /**
    437         * <p>Checks if an array of Classes can be assigned to another array of Classes.</p>
    438         *
    439         * <p>This method calls {@link #isAssignable(Class, Class) isAssignable} for each
    440         * Class pair in the input arrays. It can be used to check if a set of arguments
    441         * (the first parameter) are suitably compatible with a set of method parameter types
    442         * (the second parameter).</p>
    443         *
    444         * <p>Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, this
    445         * method takes into account widenings of primitive classes and
    446         * {@code null}s.</p>
    447         *
    448         * <p>Primitive widenings allow an int to be assigned to a {@code long},
    449         * {@code float} or {@code double}. This method returns the correct
    450         * result for these cases.</p>
    451         *
    452         * <p>{@code Null} may be assigned to any reference type. This method will
    453         * return {@code true} if {@code null} is passed in and the toClass is
    454         * non-primitive.</p>
    455         *
    456         * <p>Specifically, this method tests whether the type represented by the
    457         * specified {@code Class} parameter can be converted to the type
    458         * represented by this {@code Class} object via an identity conversion
    459         * widening primitive or widening reference conversion. See
    460         * <em><a href="http://java.sun.com/docs/books/jls/">The Java Language Specification</a></em>,
    461         * sections 5.1.1, 5.1.2 and 5.1.4 for details.</p>
    462         *
    463         * <p><strong>Since Lang 3.0,</strong> this method will default behavior for
    464         * calculating assignability between primitive and wrapper types <em>corresponding
    465         * to the running Java version</em>; i.e. autoboxing will be the default
    466         * behavior in VMs running Java versions >= 1.5.</p>
    467         *
    468         * @param classArray  the array of Classes to check, may be {@code null}
    469         * @param toClassArray  the array of Classes to try to assign into, may be {@code null}
    470         * @return {@code true} if assignment possible
    471         */
    472        public static boolean isAssignable(Class<?>[] classArray, Class<?>... toClassArray) {
    473            return isAssignable(classArray, toClassArray, SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_1_5));
    474        }
    475
    476        /**
    477         * <p>Checks if an array of Classes can be assigned to another array of Classes.</p>
    478         *
    479         * <p>This method calls {@link #isAssignable(Class, Class) isAssignable} for each
    480         * Class pair in the input arrays. It can be used to check if a set of arguments
    481         * (the first parameter) are suitably compatible with a set of method parameter types
    482         * (the second parameter).</p>
    483         *
    484         * <p>Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, this
    485         * method takes into account widenings of primitive classes and
    486         * {@code null}s.</p>
    487         *
    488         * <p>Primitive widenings allow an int to be assigned to a {@code long},
    489         * {@code float} or {@code double}. This method returns the correct
    490         * result for these cases.</p>
    491         *
    492         * <p>{@code Null} may be assigned to any reference type. This method will
    493         * return {@code true} if {@code null} is passed in and the toClass is
    494         * non-primitive.</p>
    495         *
    496         * <p>Specifically, this method tests whether the type represented by the
    497         * specified {@code Class} parameter can be converted to the type
    498         * represented by this {@code Class} object via an identity conversion
    499         * widening primitive or widening reference conversion. See
    500         * <em><a href="http://java.sun.com/docs/books/jls/">The Java Language Specification</a></em>,
    501         * sections 5.1.1, 5.1.2 and 5.1.4 for details.</p>
    502         *
    503         * @param classArray  the array of Classes to check, may be {@code null}
    504         * @param toClassArray  the array of Classes to try to assign into, may be {@code null}
    505         * @param autoboxing  whether to use implicit autoboxing/unboxing between primitives and wrappers
    506         * @return {@code true} if assignment possible
    507         */
    508        public static boolean isAssignable(Class<?>[] classArray, Class<?>[] toClassArray, boolean autoboxing) {
    509            if (ArrayUtils.isSameLength(classArray, toClassArray) == false) {
    510                return false;
    511            }
    512            if (classArray == null) {
    513                classArray = ArrayUtils.EMPTY_CLASS_ARRAY;
    514            }
    515            if (toClassArray == null) {
    516                toClassArray = ArrayUtils.EMPTY_CLASS_ARRAY;
    517            }
    518            for (int i = 0; i < classArray.length; i++) {
    519                if (isAssignable(classArray[i], toClassArray[i], autoboxing) == false) {
    520                    return false;
    521                }
    522            }
    523            return true;
    524        }
    525
    526        /**
    527         * Returns whether the given {@code type} is a primitive or primitive wrapper ({@link Boolean}, {@link Byte}, {@link Character},
    528         * {@link Short}, {@link Integer}, {@link Long}, {@link Double}, {@link Float}).
    529         *
    530         * @param type
    531         *            The class to query or null.
    532         * @return true if the given {@code type} is a primitive or primitive wrapper ({@link Boolean}, {@link Byte}, {@link Character},
    533         *         {@link Short}, {@link Integer}, {@link Long}, {@link Double}, {@link Float}).
    534         * @since 3.1
    535         */
    536        public static boolean isPrimitiveOrWrapper(Class<?> type) {
    537            if (type == null) {
    538                return false;
    539            }
    540            return type.isPrimitive() || isPrimitiveWrapper(type);
    541        }
    542
    543        /**
    544         * Returns whether the given {@code type} is a primitive wrapper ({@link Boolean}, {@link Byte}, {@link Character}, {@link Short},
    545         * {@link Integer}, {@link Long}, {@link Double}, {@link Float}).
    546         *
    547         * @param type
    548         *            The class to query or null.
    549         * @return true if the given {@code type} is a primitive wrapper ({@link Boolean}, {@link Byte}, {@link Character}, {@link Short},
    550         *         {@link Integer}, {@link Long}, {@link Double}, {@link Float}).
    551         * @since 3.1
    552         */
    553        public static boolean isPrimitiveWrapper(Class<?> type) {
    554            return wrapperPrimitiveMap.containsKey(type);
    555        }
    556
    557        /**
    558         * <p>Checks if one {@code Class} can be assigned to a variable of
    559         * another {@code Class}.</p>
    560         *
    561         * <p>Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method,
    562         * this method takes into account widenings of primitive classes and
    563         * {@code null}s.</p>
    564         *
    565         * <p>Primitive widenings allow an int to be assigned to a long, float or
    566         * double. This method returns the correct result for these cases.</p>
    567         *
    568         * <p>{@code Null} may be assigned to any reference type. This method
    569         * will return {@code true} if {@code null} is passed in and the
    570         * toClass is non-primitive.</p>
    571         *
    572         * <p>Specifically, this method tests whether the type represented by the
    573         * specified {@code Class} parameter can be converted to the type
    574         * represented by this {@code Class} object via an identity conversion
    575         * widening primitive or widening reference conversion. See
    576         * <em><a href="http://java.sun.com/docs/books/jls/">The Java Language Specification</a></em>,
    577         * sections 5.1.1, 5.1.2 and 5.1.4 for details.</p>
    578         *
    579         * <p><strong>Since Lang 3.0,</strong> this method will default behavior for
    580         * calculating assignability between primitive and wrapper types <em>corresponding
    581         * to the running Java version</em>; i.e. autoboxing will be the default
    582         * behavior in VMs running Java versions >= 1.5.</p>
    583         *
    584         * @param cls  the Class to check, may be null
    585         * @param toClass  the Class to try to assign into, returns false if null
    586         * @return {@code true} if assignment possible
    587         */
    588        public static boolean isAssignable(Class<?> cls, Class<?> toClass) {
    589            return isAssignable(cls, toClass, SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_1_5));
    590        }
    591
    592        /**
    593         * <p>Checks if one {@code Class} can be assigned to a variable of
    594         * another {@code Class}.</p>
    595         *
    596         * <p>Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method,
    597         * this method takes into account widenings of primitive classes and
    598         * {@code null}s.</p>
    599         *
    600         * <p>Primitive widenings allow an int to be assigned to a long, float or
    601         * double. This method returns the correct result for these cases.</p>
    602         *
    603         * <p>{@code Null} may be assigned to any reference type. This method
    604         * will return {@code true} if {@code null} is passed in and the
    605         * toClass is non-primitive.</p>
    606         *
    607         * <p>Specifically, this method tests whether the type represented by the
    608         * specified {@code Class} parameter can be converted to the type
    609         * represented by this {@code Class} object via an identity conversion
    610         * widening primitive or widening reference conversion. See
    611         * <em><a href="http://java.sun.com/docs/books/jls/">The Java Language Specification</a></em>,
    612         * sections 5.1.1, 5.1.2 and 5.1.4 for details.</p>
    613         *
    614         * @param cls  the Class to check, may be null
    615         * @param toClass  the Class to try to assign into, returns false if null
    616         * @param autoboxing  whether to use implicit autoboxing/unboxing between primitives and wrappers
    617         * @return {@code true} if assignment possible
    618         */
    619        public static boolean isAssignable(Class<?> cls, Class<?> toClass, boolean autoboxing) {
    620            if (toClass == null) {
    621                return false;
    622            }
    623            // have to check for null, as isAssignableFrom doesn't
    624            if (cls == null) {
    625                return !toClass.isPrimitive();
    626            }
    627            //autoboxing:
    628            if (autoboxing) {
    629                if (cls.isPrimitive() && !toClass.isPrimitive()) {
    630                    cls = primitiveToWrapper(cls);
    631                    if (cls == null) {
    632                        return false;
    633                    }
    634                }
    635                if (toClass.isPrimitive() && !cls.isPrimitive()) {
    636                    cls = wrapperToPrimitive(cls);
    637                    if (cls == null) {
    638                        return false;
    639                    }
    640                }
    641            }
    642            if (cls.equals(toClass)) {
    643                return true;
    644            }
    645            if (cls.isPrimitive()) {
    646                if (toClass.isPrimitive() == false) {
    647                    return false;
    648                }
    649                if (Integer.TYPE.equals(cls)) {
    650                    return Long.TYPE.equals(toClass)
    651                        || Float.TYPE.equals(toClass)
    652                        || Double.TYPE.equals(toClass);
    653                }
    654                if (Long.TYPE.equals(cls)) {
    655                    return Float.TYPE.equals(toClass)
    656                        || Double.TYPE.equals(toClass);
    657                }
    658                if (Boolean.TYPE.equals(cls)) {
    659                    return false;
    660                }
    661                if (Double.TYPE.equals(cls)) {
    662                    return false;
    663                }
    664                if (Float.TYPE.equals(cls)) {
    665                    return Double.TYPE.equals(toClass);
    666                }
    667                if (Character.TYPE.equals(cls)) {
    668                    return Integer.TYPE.equals(toClass)
    669                        || Long.TYPE.equals(toClass)
    670                        || Float.TYPE.equals(toClass)
    671                        || Double.TYPE.equals(toClass);
    672                }
    673                if (Short.TYPE.equals(cls)) {
    674                    return Integer.TYPE.equals(toClass)
    675                        || Long.TYPE.equals(toClass)
    676                        || Float.TYPE.equals(toClass)
    677                        || Double.TYPE.equals(toClass);
    678                }
    679                if (Byte.TYPE.equals(cls)) {
    680                    return Short.TYPE.equals(toClass)
    681                        || Integer.TYPE.equals(toClass)
    682                        || Long.TYPE.equals(toClass)
    683                        || Float.TYPE.equals(toClass)
    684                        || Double.TYPE.equals(toClass);
    685                }
    686                // should never get here
    687                return false;
    688            }
    689            return toClass.isAssignableFrom(cls);
    690        }
    691
    692        /**
    693         * <p>Converts the specified primitive Class object to its corresponding
    694         * wrapper Class object.</p>
    695         *
    696         * <p>NOTE: From v2.2, this method handles {@code Void.TYPE},
    697         * returning {@code Void.TYPE}.</p>
    698         *
    699         * @param cls  the class to convert, may be null
    700         * @return the wrapper class for {@code cls} or {@code cls} if
    701         * {@code cls} is not a primitive. {@code null} if null input.
    702         * @since 2.1
    703         */
    704        public static Class<?> primitiveToWrapper(Class<?> cls) {
    705            Class<?> convertedClass = cls;
    706            if (cls != null && cls.isPrimitive()) {
    707                convertedClass = primitiveWrapperMap.get(cls);
    708            }
    709            return convertedClass;
    710        }
    711
    712        /**
    713         * <p>Converts the specified array of primitive Class objects to an array of
    714         * its corresponding wrapper Class objects.</p>
    715         *
    716         * @param classes  the class array to convert, may be null or empty
    717         * @return an array which contains for each given class, the wrapper class or
    718         * the original class if class is not a primitive. {@code null} if null input.
    719         * Empty array if an empty array passed in.
    720         * @since 2.1
    721         */
    722        public static Class<?>[] primitivesToWrappers(Class<?>... classes) {
    723            if (classes == null) {
    724                return null;
    725            }
    726
    727            if (classes.length == 0) {
    728                return classes;
    729            }
    730
    731            Class<?>[] convertedClasses = new Class[classes.length];
    732            for (int i = 0; i < classes.length; i++) {
    733                convertedClasses[i] = primitiveToWrapper(classes[i]);
    734            }
    735            return convertedClasses;
    736        }
    737
    738        /**
    739         * <p>Converts the specified wrapper class to its corresponding primitive
    740         * class.</p>
    741         *
    742         * <p>This method is the counter part of {@code primitiveToWrapper()}.
    743         * If the passed in class is a wrapper class for a primitive type, this
    744         * primitive type will be returned (e.g. {@code Integer.TYPE} for
    745         * {@code Integer.class}). For other classes, or if the parameter is
    746         * <b>null</b>, the return value is <b>null</b>.</p>
    747         *
    748         * @param cls the class to convert, may be <b>null</b>
    749         * @return the corresponding primitive type if {@code cls} is a
    750         * wrapper class, <b>null</b> otherwise
    751         * @see #primitiveToWrapper(Class)
    752         * @since 2.4
    753         */
    754        public static Class<?> wrapperToPrimitive(Class<?> cls) {
    755            return wrapperPrimitiveMap.get(cls);
    756        }
    757
    758        /**
    759         * <p>Converts the specified array of wrapper Class objects to an array of
    760         * its corresponding primitive Class objects.</p>
    761         *
    762         * <p>This method invokes {@code wrapperToPrimitive()} for each element
    763         * of the passed in array.</p>
    764         *
    765         * @param classes  the class array to convert, may be null or empty
    766         * @return an array which contains for each given class, the primitive class or
    767         * <b>null</b> if the original class is not a wrapper class. {@code null} if null input.
    768         * Empty array if an empty array passed in.
    769         * @see #wrapperToPrimitive(Class)
    770         * @since 2.4
    771         */
    772        public static Class<?>[] wrappersToPrimitives(Class<?>... classes) {
    773            if (classes == null) {
    774                return null;
    775            }
    776
    777            if (classes.length == 0) {
    778                return classes;
    779            }
    780
    781            Class<?>[] convertedClasses = new Class[classes.length];
    782            for (int i = 0; i < classes.length; i++) {
    783                convertedClasses[i] = wrapperToPrimitive(classes[i]);
    784            }
    785            return convertedClasses;
    786        }
    787
    788        // Inner class
    789        // ----------------------------------------------------------------------
    790        /**
    791         * <p>Is the specified class an inner class or static nested class.</p>
    792         *
    793         * @param cls  the class to check, may be null
    794         * @return {@code true} if the class is an inner or static nested class,
    795         *  false if not or {@code null}
    796         */
    797        public static boolean isInnerClass(Class<?> cls) {
    798            return cls != null && cls.getEnclosingClass() != null;
    799        }
    800
    801        // Class loading
    802        // ----------------------------------------------------------------------
    803        /**
    804         * Returns the class represented by {@code className} using the
    805         * {@code classLoader}.  This implementation supports the syntaxes
    806         * "{@code java.util.Map.Entry[]}", "{@code java.util.Map$Entry[]}",
    807         * "{@code [Ljava.util.Map.Entry;}", and "{@code [Ljava.util.Map$Entry;}".
    808         *
    809         * @param classLoader  the class loader to use to load the class
    810         * @param className  the class name
    811         * @param initialize  whether the class must be initialized
    812         * @return the class represented by {@code className} using the {@code classLoader}
    813         * @throws ClassNotFoundException if the class is not found
    814         */
    815        public static Class<?> getClass(
    816                ClassLoader classLoader, String className, boolean initialize) throws ClassNotFoundException {
    817            try {
    818                Class<?> clazz;
    819                if (abbreviationMap.containsKey(className)) {
    820                    String clsName = "[" + abbreviationMap.get(className);
    821                    clazz = Class.forName(clsName, initialize, classLoader).getComponentType();
    822                } else {
    823                    clazz = Class.forName(toCanonicalName(className), initialize, classLoader);
    824                }
    825                return clazz;
    826            } catch (ClassNotFoundException ex) {
    827                // allow path separators (.) as inner class name separators
    828                int lastDotIndex = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR);
    829
    830                if (lastDotIndex != -1) {
    831                    try {
    832                        return getClass(classLoader, className.substring(0, lastDotIndex) +
    833                                INNER_CLASS_SEPARATOR_CHAR + className.substring(lastDotIndex + 1),
    834                                initialize);
    835                    } catch (ClassNotFoundException ex2) { // NOPMD
    836                        // ignore exception
    837                    }
    838                }
    839
    840                throw ex;
    841            }
    842        }
    843
    844        /**
    845         * Returns the (initialized) class represented by {@code className}
    846         * using the {@code classLoader}.  This implementation supports
    847         * the syntaxes "{@code java.util.Map.Entry[]}",
    848         * "{@code java.util.Map$Entry[]}", "{@code [Ljava.util.Map.Entry;}",
    849         * and "{@code [Ljava.util.Map$Entry;}".
    850         *
    851         * @param classLoader  the class loader to use to load the class
    852         * @param className  the class name
    853         * @return the class represented by {@code className} using the {@code classLoader}
    854         * @throws ClassNotFoundException if the class is not found
    855         */
    856        public static Class<?> getClass(ClassLoader classLoader, String className) throws ClassNotFoundException {
    857            return getClass(classLoader, className, true);
    858        }
    859
    860        /**
    861         * Returns the (initialized) class represented by {@code className}
    862         * using the current thread's context class loader. This implementation
    863         * supports the syntaxes "{@code java.util.Map.Entry[]}",
    864         * "{@code java.util.Map$Entry[]}", "{@code [Ljava.util.Map.Entry;}",
    865         * and "{@code [Ljava.util.Map$Entry;}".
    866         *
    867         * @param className  the class name
    868         * @return the class represented by {@code className} using the current thread's context class loader
    869         * @throws ClassNotFoundException if the class is not found
    870         */
    871        public static Class<?> getClass(String className) throws ClassNotFoundException {
    872            return getClass(className, true);
    873        }
    874
    875        /**
    876         * Returns the class represented by {@code className} using the
    877         * current thread's context class loader. This implementation supports the
    878         * syntaxes "{@code java.util.Map.Entry[]}", "{@code java.util.Map$Entry[]}",
    879         * "{@code [Ljava.util.Map.Entry;}", and "{@code [Ljava.util.Map$Entry;}".
    880         *
    881         * @param className  the class name
    882         * @param initialize  whether the class must be initialized
    883         * @return the class represented by {@code className} using the current thread's context class loader
    884         * @throws ClassNotFoundException if the class is not found
    885         */
    886        public static Class<?> getClass(String className, boolean initialize) throws ClassNotFoundException {
    887            ClassLoader contextCL = Thread.currentThread().getContextClassLoader();
    888            ClassLoader loader = contextCL == null ? ClassUtils.class.getClassLoader() : contextCL;
    889            return getClass(loader, className, initialize);
    890        }
    891
    892        // Public method
    893        // ----------------------------------------------------------------------
    894        /**
    895         * <p>Returns the desired Method much like {@code Class.getMethod}, however
    896         * it ensures that the returned Method is from a public class or interface and not
    897         * from an anonymous inner class. This means that the Method is invokable and
    898         * doesn't fall foul of Java bug
    899         * <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4071957">4071957</a>).
    900         *
    901         *  <code><pre>Set set = Collections.unmodifiableSet(...);
    902         *  Method method = ClassUtils.getPublicMethod(set.getClass(), "isEmpty",  new Class[0]);
    903         *  Object result = method.invoke(set, new Object[]);</pre></code>
    904         * </p>
    905         *
    906         * @param cls  the class to check, not null
    907         * @param methodName  the name of the method
    908         * @param parameterTypes  the list of parameters
    909         * @return the method
    910         * @throws NullPointerException if the class is null
    911         * @throws SecurityException if a a security violation occured
    912         * @throws NoSuchMethodException if the method is not found in the given class
    913         *  or if the metothod doen't conform with the requirements
    914         */
    915        public static Method getPublicMethod(Class<?> cls, String methodName, Class<?>... parameterTypes)
    916                throws SecurityException, NoSuchMethodException {
    917
    918            Method declaredMethod = cls.getMethod(methodName, parameterTypes);
    919            if (Modifier.isPublic(declaredMethod.getDeclaringClass().getModifiers())) {
    920                return declaredMethod;
    921            }
    922
    923            List<Class<?>> candidateClasses = new ArrayList<Class<?>>();
    924            candidateClasses.addAll(getAllInterfaces(cls));
    925            candidateClasses.addAll(getAllSuperclasses(cls));
    926
    927            for (Class<?> candidateClass : candidateClasses) {
    928                if (!Modifier.isPublic(candidateClass.getModifiers())) {
    929                    continue;
    930                }
    931                Method candidateMethod;
    932                try {
    933                    candidateMethod = candidateClass.getMethod(methodName, parameterTypes);
    934                } catch (NoSuchMethodException ex) {
    935                    continue;
    936                }
    937                if (Modifier.isPublic(candidateMethod.getDeclaringClass().getModifiers())) {
    938                    return candidateMethod;
    939                }
    940            }
    941
    942            throw new NoSuchMethodException("Can't find a public method for " +
    943                    methodName + " " + ArrayUtils.toString(parameterTypes));
    944        }
    945
    946        // ----------------------------------------------------------------------
    947        /**
    948         * Converts a class name to a JLS style class name.
    949         *
    950         * @param className  the class name
    951         * @return the converted name
    952         */
    953        private static String toCanonicalName(String className) {
    954            className = StringUtils.deleteWhitespace(className);
    955            if (className == null) {
    956                throw new NullPointerException("className must not be null.");
    957            } else if (className.endsWith("[]")) {
    958                StringBuilder classNameBuffer = new StringBuilder();
    959                while (className.endsWith("[]")) {
    960                    className = className.substring(0, className.length() - 2);
    961                    classNameBuffer.append("[");
    962                }
    963                String abbreviation = abbreviationMap.get(className);
    964                if (abbreviation != null) {
    965                    classNameBuffer.append(abbreviation);
    966                } else {
    967                    classNameBuffer.append("L").append(className).append(";");
    968                }
    969                className = classNameBuffer.toString();
    970            }
    971            return className;
    972        }
    973
    974        /**
    975         * <p>Converts an array of {@code Object} in to an array of {@code Class} objects.
    976         * If any of these objects is null, a null element will be inserted into the array.</p>
    977         *
    978         * <p>This method returns {@code null} for a {@code null} input array.</p>
    979         *
    980         * @param array an {@code Object} array
    981         * @return a {@code Class} array, {@code null} if null array input
    982         * @since 2.4
    983         */
    984        public static Class<?>[] toClass(Object... array) {
    985            if (array == null) {
    986                return null;
    987            } else if (array.length == 0) {
    988                return ArrayUtils.EMPTY_CLASS_ARRAY;
    989            }
    990            Class<?>[] classes = new Class[array.length];
    991            for (int i = 0; i < array.length; i++) {
    992                classes[i] = array[i] == null ? null : array[i].getClass();
    993            }
    994            return classes;
    995        }
    996
    997        // Short canonical name
    998        // ----------------------------------------------------------------------
    999        /**
    1000         * <p>Gets the canonical name minus the package name for an {@code Object}.</p>
    1001         *
    1002         * @param object  the class to get the short name for, may be null
    1003         * @param valueIfNull  the value to return if null
    1004         * @return the canonical name of the object without the package name, or the null value
    1005         * @since 2.4
    1006         */
    1007        public static String getShortCanonicalName(Object object, String valueIfNull) {
    1008            if (object == null) {
    1009                return valueIfNull;
    1010            }
    1011            return getShortCanonicalName(object.getClass().getName());
    1012        }
    1013
    1014        /**
    1015         * <p>Gets the canonical name minus the package name from a {@code Class}.</p>
    1016         *
    1017         * @param cls  the class to get the short name for.
    1018         * @return the canonical name without the package name or an empty string
    1019         * @since 2.4
    1020         */
    1021        public static String getShortCanonicalName(Class<?> cls) {
    1022            if (cls == null) {
    1023                return StringUtils.EMPTY;
    1024            }
    1025            return getShortCanonicalName(cls.getName());
    1026        }
    1027
    1028        /**
    1029         * <p>Gets the canonical name minus the package name from a String.</p>
    1030         *
    1031         * <p>The string passed in is assumed to be a canonical name - it is not checked.</p>
    1032         *
    1033         * @param canonicalName  the class name to get the short name for
    1034         * @return the canonical name of the class without the package name or an empty string
    1035         * @since 2.4
    1036         */
    1037        public static String getShortCanonicalName(String canonicalName) {
    1038            return ClassUtils.getShortClassName(getCanonicalName(canonicalName));
    1039        }
    1040
    1041        // Package name
    1042        // ----------------------------------------------------------------------
    1043        /**
    1044         * <p>Gets the package name from the canonical name of an {@code Object}.</p>
    1045         *
    1046         * @param object  the class to get the package name for, may be null
    1047         * @param valueIfNull  the value to return if null
    1048         * @return the package name of the object, or the null value
    1049         * @since 2.4
    1050         */
    1051        public static String getPackageCanonicalName(Object object, String valueIfNull) {
    1052            if (object == null) {
    1053                return valueIfNull;
    1054            }
    1055            return getPackageCanonicalName(object.getClass().getName());
    1056        }
    1057
    1058        /**
    1059         * <p>Gets the package name from the canonical name of a {@code Class}.</p>
    1060         *
    1061         * @param cls  the class to get the package name for, may be {@code null}.
    1062         * @return the package name or an empty string
    1063         * @since 2.4
    1064         */
    1065        public static String getPackageCanonicalName(Class<?> cls) {
    1066            if (cls == null) {
    1067                return StringUtils.EMPTY;
    1068            }
    1069            return getPackageCanonicalName(cls.getName());
    1070        }
    1071
    1072        /**
    1073         * <p>Gets the package name from the canonical name. </p>
    1074         *
    1075         * <p>The string passed in is assumed to be a canonical name - it is not checked.</p>
    1076         * <p>If the class is unpackaged, return an empty string.</p>
    1077         *
    1078         * @param canonicalName  the canonical name to get the package name for, may be {@code null}
    1079         * @return the package name or an empty string
    1080         * @since 2.4
    1081         */
    1082        public static String getPackageCanonicalName(String canonicalName) {
    1083            return ClassUtils.getPackageName(getCanonicalName(canonicalName));
    1084        }
    1085
    1086        /**
    1087         * <p>Converts a given name of class into canonical format.
    1088         * If name of class is not a name of array class it returns
    1089         * unchanged name.</p>
    1090         * <p>Example:
    1091         * <ul>
    1092         * <li>{@code getCanonicalName("[I") = "int[]"}</li>
    1093         * <li>{@code getCanonicalName("[Ljava.lang.String;") = "java.lang.String[]"}</li>
    1094         * <li>{@code getCanonicalName("java.lang.String") = "java.lang.String"}</li>
    1095         * </ul>
    1096         * </p>
    1097         *
    1098         * @param className the name of class
    1099         * @return canonical form of class name
    1100         * @since 2.4
    1101         */
    1102        private static String getCanonicalName(String className) {
    1103            className = StringUtils.deleteWhitespace(className);
    1104            if (className == null) {
    1105                return null;
    1106            } else {
    1107                int dim = 0;
    1108                while (className.startsWith("[")) {
    1109                    dim++;
    1110                    className = className.substring(1);
    1111                }
    1112                if (dim < 1) {
    1113                    return className;
    1114                } else {
    1115                    if (className.startsWith("L")) {
    1116                        className = className.substring(
    1117                            1,
    1118                            className.endsWith(";")
    1119                                ? className.length() - 1
    1120                                : className.length());
    1121                    } else {
    1122                        if (className.length() > 0) {
    1123                            className = reverseAbbreviationMap.get(className.substring(0, 1));
    1124                        }
    1125                    }
    1126                    StringBuilder canonicalClassNameBuffer = new StringBuilder(className);
    1127                    for (int i = 0; i < dim; i++) {
    1128                        canonicalClassNameBuffer.append("[]");
    1129                    }
    1130                    return canonicalClassNameBuffer.toString();
    1131                }
    1132            }
    1133        }
    1134
    1135    }