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