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