    001/*
    002 * Licensed to the Apache Software Foundation (ASF) under one or more
    003 * contributor license agreements.  See the NOTICE file distributed with
    004 * this work for additional information regarding copyright ownership.
    005 * The ASF licenses this file to You under the Apache License, Version 2.0
    006 * (the "License"); you may not use this file except in compliance with
    007 * the License.  You may obtain a copy of the License at
    008 *
    009 *      http://www.apache.org/licenses/LICENSE-2.0
    010 *
    011 * Unless required by applicable law or agreed to in writing, software
    012 * distributed under the License is distributed on an "AS IS" BASIS,
    013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014 * See the License for the specific language governing permissions and
    015 * limitations under the License.
    016 */
    017package org.apache.commons.lang3;
    018
    019import java.lang.reflect.Method;
    020import java.lang.reflect.Modifier;
    021import java.util.ArrayList;
    022import java.util.Collections;
    023import java.util.HashMap;
    024import java.util.HashSet;
    025import java.util.Iterator;
    026import java.util.LinkedHashSet;
    027import java.util.List;
    028import java.util.Map;
    029import java.util.Set;
    030
    031import org.apache.commons.lang3.mutable.MutableObject;
    032
    033/**
    034 * <p>Operates on classes without using reflection.</p>
    035 *
    036 * <p>This class handles invalid {@code null} inputs as best it can.
    037 * Each method documents its behaviour in more detail.</p>
    038 *
    039 * <p>The notion of a {@code canonical name} includes the human
    040 * readable name for the type, for example {@code int[]}. The
    041 * non-canonical method variants work with the JVM names, such as
    042 * {@code [I}. </p>
    043 *
    044 * @since 2.0
    045 */
    046public class ClassUtils {
    047
    048    /**
    049     * Inclusivity literals for {@link #hierarchy(Class, Interfaces)}.
    050     * @since 3.2
    051     */
    052    public enum Interfaces {
    053        INCLUDE, EXCLUDE
    054    }
    055
    056    /**
    057     * The package separator character: <code>'&#x2e;' == {@value}</code>.
    058     */
    059    public static final char PACKAGE_SEPARATOR_CHAR = '.';
    060
    061    /**
    062     * The package separator String: <code>"&#x2e;"</code>.
    063     */
    064    public static final String PACKAGE_SEPARATOR = String.valueOf(PACKAGE_SEPARATOR_CHAR);
    065
    066    /**
    067     * The inner class separator character: <code>'$' == {@value}</code>.
    068     */
    069    public static final char INNER_CLASS_SEPARATOR_CHAR = '$';
    070
    071    /**
    072     * The inner class separator String: {@code "$"}.
    073     */
    074    public static final String INNER_CLASS_SEPARATOR = String.valueOf(INNER_CLASS_SEPARATOR_CHAR);
    075
    076    /**
    077     * Maps names of primitives to their corresponding primitive {@code Class}es.
    078     */
    079    private static final Map<String, Class<?>> namePrimitiveMap = new HashMap<>();
    080    static {
    081         namePrimitiveMap.put("boolean", Boolean.TYPE);
    082         namePrimitiveMap.put("byte", Byte.TYPE);
    083         namePrimitiveMap.put("char", Character.TYPE);
    084         namePrimitiveMap.put("short", Short.TYPE);
    085         namePrimitiveMap.put("int", Integer.TYPE);
    086         namePrimitiveMap.put("long", Long.TYPE);
    087         namePrimitiveMap.put("double", Double.TYPE);
    088         namePrimitiveMap.put("float", Float.TYPE);
    089         namePrimitiveMap.put("void", Void.TYPE);
    090    }
    091
    092    /**
    093     * Maps primitive {@code Class}es to their corresponding wrapper {@code Class}.
    094     */
    095    private static final Map<Class<?>, Class<?>> primitiveWrapperMap = new HashMap<>();
    096    static {
    097         primitiveWrapperMap.put(Boolean.TYPE, Boolean.class);
    098         primitiveWrapperMap.put(Byte.TYPE, Byte.class);
    099         primitiveWrapperMap.put(Character.TYPE, Character.class);
    100         primitiveWrapperMap.put(Short.TYPE, Short.class);
    101         primitiveWrapperMap.put(Integer.TYPE, Integer.class);
    102         primitiveWrapperMap.put(Long.TYPE, Long.class);
    103         primitiveWrapperMap.put(Double.TYPE, Double.class);
    104         primitiveWrapperMap.put(Float.TYPE, Float.class);
    105         primitiveWrapperMap.put(Void.TYPE, Void.TYPE);
    106    }
    107
    108    /**
    109     * Maps wrapper {@code Class}es to their corresponding primitive types.
    110     */
    111    private static final Map<Class<?>, Class<?>> wrapperPrimitiveMap = new HashMap<>();
    112    static {
    113        for (final Map.Entry<Class<?>, Class<?>> entry : primitiveWrapperMap.entrySet()) {
    114            final Class<?> primitiveClass = entry.getKey();
    115            final Class<?> wrapperClass = entry.getValue();
    116            if (!primitiveClass.equals(wrapperClass)) {
    117                wrapperPrimitiveMap.put(wrapperClass, primitiveClass);
    118            }
    119        }
    120    }
    121
    122    /**
    123     * Maps a primitive class name to its corresponding abbreviation used in array class names.
    124     */
    125    private static final Map<String, String> abbreviationMap;
    126
    127    /**
    128     * Maps an abbreviation used in array class names to corresponding primitive class name.
    129     */
    130    private static final Map<String, String> reverseAbbreviationMap;
    131
    132    /**
    133     * Feed abbreviation maps
    134     */
    135    static {
    136        final Map<String, String> m = new HashMap<>();
    137        m.put("int", "I");
    138        m.put("boolean", "Z");
    139        m.put("float", "F");
    140        m.put("long", "J");
    141        m.put("short", "S");
    142        m.put("byte", "B");
    143        m.put("double", "D");
    144        m.put("char", "C");
    145        final Map<String, String> r = new HashMap<>();
    146        for (final Map.Entry<String, String> e : m.entrySet()) {
    147            r.put(e.getValue(), e.getKey());
    148        }
    149        abbreviationMap = Collections.unmodifiableMap(m);
    150        reverseAbbreviationMap = Collections.unmodifiableMap(r);
    151    }
    152
    153    /**
    154     * <p>ClassUtils instances should NOT be constructed in standard programming.
    155     * Instead, the class should be used as
    156     * {@code ClassUtils.getShortClassName(cls)}.</p>
    157     *
    158     * <p>This constructor is public to permit tools that require a JavaBean
    159     * instance to operate.</p>
    160     */
    161    public ClassUtils() {
    162      super();
    163    }
    164
    165    // Short class name
    166    // ----------------------------------------------------------------------
    167    /**
    168     * <p>Gets the class name minus the package name for an {@code Object}.</p>
    169     *
    170     * @param object  the class to get the short name for, may be null
    171     * @param valueIfNull  the value to return if null
    172     * @return the class name of the object without the package name, or the null value
    173     */
    174    public static String getShortClassName(final Object object, final String valueIfNull) {
    175        if (object == null) {
    176            return valueIfNull;
    177        }
    178        return getShortClassName(object.getClass());
    179    }
    180
    181    /**
    182     * <p>Gets the class name minus the package name from a {@code Class}.</p>
    183     *
    184     * <p>Consider using the Java 5 API {@link Class#getSimpleName()} instead.
    185     * The one known difference is that this code will return {@code "Map.Entry"} while
    186     * the {@code java.lang.Class} variant will simply return {@code "Entry"}. </p>
    187     *
    188     * @param cls  the class to get the short name for.
    189     * @return the class name without the package name or an empty string
    190     */
    191    public static String getShortClassName(final Class<?> cls) {
    192        if (cls == null) {
    193            return StringUtils.EMPTY;
    194        }
    195        return getShortClassName(cls.getName());
    196    }
    197
    198    /**
    199     * <p>Gets the class name minus the package name from a String.</p>
    200     *
    201     * <p>The string passed in is assumed to be a class name - it is not checked.</p>
    202
    203     * <p>Note that this method differs from Class.getSimpleName() in that this will
    204     * return {@code "Map.Entry"} whilst the {@code java.lang.Class} variant will simply
    205     * return {@code "Entry"}. </p>
    206     *
    207     * @param className  the className to get the short name for
    208     * @return the class name of the class without the package name or an empty string
    209     */
    210    public static String getShortClassName(String className) {
    211        if (StringUtils.isEmpty(className)) {
    212            return StringUtils.EMPTY;
    213        }
    214
    215        final StringBuilder arrayPrefix = new StringBuilder();
    216
    217        // Handle array encoding
    218        if (className.startsWith("[")) {
    219            while (className.charAt(0) == '[') {
    220                className = className.substring(1);
    221                arrayPrefix.append("[]");
    222            }
    223            // Strip Object type encoding
    224            if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';') {
    225                className = className.substring(1, className.length() - 1);
    226            }
    227
    228            if (reverseAbbreviationMap.containsKey(className)) {
    229                className = reverseAbbreviationMap.get(className);
    230            }
    231        }
    232
    233        final int lastDotIdx = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR);
    234        final int innerIdx = className.indexOf(
    235                INNER_CLASS_SEPARATOR_CHAR, lastDotIdx == -1 ? 0 : lastDotIdx + 1);
    236        String out = className.substring(lastDotIdx + 1);
    237        if (innerIdx != -1) {
    238            out = out.replace(INNER_CLASS_SEPARATOR_CHAR, PACKAGE_SEPARATOR_CHAR);
    239        }
    240        return out + arrayPrefix;
    241    }
    242
    243    /**
    244     * <p>Null-safe version of <code>aClass.getSimpleName()</code></p>
    245     *
    246     * @param cls the class for which to get the simple name; may be null
    247     * @return the simple class name.
    248     * @since 3.0
    249     * @see Class#getSimpleName()
    250     */
    251    public static String getSimpleName(final Class<?> cls) {
    252        return getSimpleName(cls, StringUtils.EMPTY);
    253    }
    254
    255    /**
    256     * <p>Null-safe version of <code>aClass.getSimpleName()</code></p>
    257     *
    258     * @param cls the class for which to get the simple name; may be null
    259     * @param valueIfNull  the value to return if null
    260     * @return the simple class name or {@code valueIfNull}
    261     * @since 3.0
    262     * @see Class#getSimpleName()
    263     */
    264    public static String getSimpleName(final Class<?> cls, String valueIfNull) {
    265        return cls == null ? valueIfNull : cls.getSimpleName();
    266    }
    267
    268    /**
    269     * <p>Null-safe version of <code>aClass.getSimpleName()</code></p>
    270     *
    271     * @param object the object for which to get the simple class name; may be null
    272     * @return the simple class name or the empty String
    273     * @since 3.7
    274     * @see Class#getSimpleName()
    275     */
    276    public static String getSimpleName(final Object object) {
    277        return getSimpleName(object, StringUtils.EMPTY);
    278    }
    279
    280    /**
    281     * <p>Null-safe version of <code>aClass.getSimpleName()</code></p>
    282     *
    283     * @param object the object for which to get the simple class name; may be null
    284     * @param valueIfNull the value to return if <code>object</code> is <code>null</code>
    285     * @return the simple class name or {@code valueIfNull}
    286     * @since 3.0
    287     * @see Class#getSimpleName()
    288     */
    289    public static String getSimpleName(final Object object, final String valueIfNull) {
    290        return object == null ? valueIfNull : object.getClass().getSimpleName();
    291    }
    292
    293    /**
    294     * <p>Null-safe version of <code>Class.getName()</code></p>
    295     *
    296     * @param cls the class for which to get the class name; may be null
    297     * @return the class name or the empty String.
    298     * @since 3.7
    299     * @see Class#getSimpleName()
    300     */
    301    public static String getName(final Class<?> cls) {
    302        return getName(cls, StringUtils.EMPTY);
    303    }
    304
    305    /**
    306     * <p>Null-safe version of <code>aClass.getName()</code></p>
    307     *
    308     * @param cls the class for which to get the class name; may be null
    309     * @param valueIfNull the return value if <code>cls</code> is <code>null</code>
    310     * @return the class name or {@code valueIfNull}
    311     * @since 3.7
    312     * @see Class#getName()
    313     */
    314    public static String getName(final Class<?> cls, final String valueIfNull) {
    315        return cls == null ? valueIfNull : cls.getName();
    316    }
    317
    318    /**
    319     * <p>Null-safe version of <code>Class.getName()</code></p>
    320     *
    321     * @param object the object for which to get the class name; may be null
    322     * @return the class name or the empty String
    323     * @since 3.7
    324     * @see Class#getSimpleName()
    325     */
    326    public static String getName(final Object object) {
    327        return getName(object, StringUtils.EMPTY);
    328    }
    329
    330    /**
    331     * <p>Null-safe version of <code>aClass.getSimpleName()</code></p>
    332     *
    333     * @param object the object for which to get the class name; may be null
    334     * @param valueIfNull the value to return if <code>object</code> is <code>null</code>
    335     * @return the class name or {@code valueIfNull}
    336     * @since 3.0
    337     * @see Class#getName()
    338     */
    339    public static String getName(final Object object, final String valueIfNull) {
    340        return object == null ? valueIfNull : object.getClass().getName();
    341    }
    342
    343    // Package name
    344    // ----------------------------------------------------------------------
    345    /**
    346     * <p>Gets the package name of an {@code Object}.</p>
    347     *
    348     * @param object  the class to get the package name for, may be null
    349     * @param valueIfNull  the value to return if null
    350     * @return the package name of the object, or the null value
    351     */
    352    public static String getPackageName(final Object object, final String valueIfNull) {
    353        if (object == null) {
    354            return valueIfNull;
    355        }
    356        return getPackageName(object.getClass());
    357    }
    358
    359    /**
    360     * <p>Gets the package name of a {@code Class}.</p>
    361     *
    362     * @param cls  the class to get the package name for, may be {@code null}.
    363     * @return the package name or an empty string
    364     */
    365    public static String getPackageName(final Class<?> cls) {
    366        if (cls == null) {
    367            return StringUtils.EMPTY;
    368        }
    369        return getPackageName(cls.getName());
    370    }
    371
    372    /**
    373     * <p>Gets the package name from a {@code String}.</p>
    374     *
    375     * <p>The string passed in is assumed to be a class name - it is not checked.</p>
    376     * <p>If the class is unpackaged, return an empty string.</p>
    377     *
    378     * @param className  the className to get the package name for, may be {@code null}
    379     * @return the package name or an empty string
    380     */
    381    public static String getPackageName(String className) {
    382        if (StringUtils.isEmpty(className)) {
    383            return StringUtils.EMPTY;
    384        }
    385
    386        // Strip array encoding
    387        while (className.charAt(0) == '[') {
    388            className = className.substring(1);
    389        }
    390        // Strip Object type encoding
    391        if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';') {
    392            className = className.substring(1);
    393        }
    394
    395        final int i = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR);
    396        if (i == -1) {
    397            return StringUtils.EMPTY;
    398        }
    399        return className.substring(0, i);
    400    }
    401
    402    // Abbreviated name
    403    // ----------------------------------------------------------------------
    404    /**
    405     * <p>Gets the abbreviated name of a {@code Class}.</p>
    406     *
    407     * @param cls  the class to get the abbreviated name for, may be {@code null}
    408     * @param len  the desired length of the abbreviated name
    409     * @return the abbreviated name or an empty string
    410     * @throws IllegalArgumentException if len &lt;= 0
    411     * @see #getAbbreviatedName(String, int)
    412     * @since 3.4
    413     */
    414    public static String getAbbreviatedName(final Class<?> cls, final int len) {
    415      if (cls == null) {
    416        return StringUtils.EMPTY;
    417      }
    418      return getAbbreviatedName(cls.getName(), len);
    419    }
    420
    421    /**
    422     * <p>Gets the abbreviated class name from a {@code String}.</p>
    423     *
    424     * <p>The string passed in is assumed to be a class name - it is not checked.</p>
    425     *
    426     * <p>The abbreviation algorithm will shorten the class name, usually without
    427     * significant loss of meaning.</p>
    428     * <p>The abbreviated class name will always include the complete package hierarchy.
    429     * If enough space is available, rightmost sub-packages will be displayed in full
    430     * length.</p>
    431     *
    432     * <table>
    433     * <caption>Examples</caption>
    434     * <tr><td>className</td><td>len</td><td>return</td></tr>
    435     * <tr><td>              null</td><td> 1</td><td>""</td></tr>
    436     * <tr><td>"java.lang.String"</td><td> 5</td><td>"j.l.String"</td></tr>
    437     * <tr><td>"java.lang.String"</td><td>15</td><td>"j.lang.String"</td></tr>
    438     * <tr><td>"java.lang.String"</td><td>30</td><td>"java.lang.String"</td></tr>
    439     * </table>
    440     * @param className  the className to get the abbreviated name for, may be {@code null}
    441     * @param len  the desired length of the abbreviated name
    442     * @return the abbreviated name or an empty string
    443     * @throws IllegalArgumentException if len &lt;= 0
    444     * @since 3.4
    445     */
    446    public static String getAbbreviatedName(final String className, final int len) {
    447      if (len <= 0) {
    448        throw new IllegalArgumentException("len must be > 0");
    449      }
    450      if (className == null) {
    451        return StringUtils.EMPTY;
    452      }
    453
    454      int availableSpace = len;
    455      final int packageLevels = StringUtils.countMatches(className, '.');
    456      final String[] output = new String[packageLevels + 1];
    457      int endIndex = className.length() - 1;
    458      for (int level = packageLevels; level >= 0; level--) {
    459        final int startIndex = className.lastIndexOf('.', endIndex);
    460        final String part = className.substring(startIndex + 1, endIndex + 1);
    461        availableSpace -= part.length();
    462        if (level > 0) {
    463          // all elements except top level require an additional char space
    464          availableSpace--;
    465        }
    466        if (level == packageLevels) {
    467          // ClassName is always complete
    468          output[level] = part;
    469        } else {
    470          if (availableSpace > 0) {
    471            output[level] = part;
    472          } else {
    473            // if no space is left still the first char is used
    474            output[level] = part.substring(0, 1);
    475          }
    476        }
    477        endIndex = startIndex - 1;
    478      }
    479
    480      return StringUtils.join(output, '.');
    481    }
    482
    483    // Superclasses/Superinterfaces
    484    // ----------------------------------------------------------------------
    485    /**
    486     * <p>Gets a {@code List} of superclasses for the given class.</p>
    487     *
    488     * @param cls  the class to look up, may be {@code null}
    489     * @return the {@code List} of superclasses in order going up from this one
    490     *  {@code null} if null input
    491     */
    492    public static List<Class<?>> getAllSuperclasses(final Class<?> cls) {
    493        if (cls == null) {
    494            return null;
    495        }
    496        final List<Class<?>> classes = new ArrayList<>();
    497        Class<?> superclass = cls.getSuperclass();
    498        while (superclass != null) {
    499            classes.add(superclass);
    500            superclass = superclass.getSuperclass();
    501        }
    502        return classes;
    503    }
    504
    505    /**
    506     * <p>Gets a {@code List} of all interfaces implemented by the given
    507     * class and its superclasses.</p>
    508     *
    509     * <p>The order is determined by looking through each interface in turn as
    510     * declared in the source file and following its hierarchy up. Then each
    511     * superclass is considered in the same way. Later duplicates are ignored,
    512     * so the order is maintained.</p>
    513     *
    514     * @param cls  the class to look up, may be {@code null}
    515     * @return the {@code List} of interfaces in order,
    516     *  {@code null} if null input
    517     */
    518    public static List<Class<?>> getAllInterfaces(final Class<?> cls) {
    519        if (cls == null) {
    520            return null;
    521        }
    522
    523        final LinkedHashSet<Class<?>> interfacesFound = new LinkedHashSet<>();
    524        getAllInterfaces(cls, interfacesFound);
    525
    526        return new ArrayList<>(interfacesFound);
    527    }
    528
    529    /**
    530     * Get the interfaces for the specified class.
    531     *
    532     * @param cls  the class to look up, may be {@code null}
    533     * @param interfacesFound the {@code Set} of interfaces for the class
    534     */
    535    private static void getAllInterfaces(Class<?> cls, final HashSet<Class<?>> interfacesFound) {
    536        while (cls != null) {
    537            final Class<?>[] interfaces = cls.getInterfaces();
    538
    539            for (final Class<?> i : interfaces) {
    540                if (interfacesFound.add(i)) {
    541                    getAllInterfaces(i, interfacesFound);
    542                }
    543            }
    544
    545            cls = cls.getSuperclass();
    546         }
    547     }
    548
    549    // Convert list
    550    // ----------------------------------------------------------------------
    551    /**
    552     * <p>Given a {@code List} of class names, this method converts them into classes.</p>
    553     *
    554     * <p>A new {@code List} is returned. If the class name cannot be found, {@code null}
    555     * is stored in the {@code List}. If the class name in the {@code List} is
    556     * {@code null}, {@code null} is stored in the output {@code List}.</p>
    557     *
    558     * @param classNames  the classNames to change
    559     * @return a {@code List} of Class objects corresponding to the class names,
    560     *  {@code null} if null input
    561     * @throws ClassCastException if classNames contains a non String entry
    562     */
    563    public static List<Class<?>> convertClassNamesToClasses(final List<String> classNames) {
    564        if (classNames == null) {
    565            return null;
    566        }
    567        final List<Class<?>> classes = new ArrayList<>(classNames.size());
    568        for (final String className : classNames) {
    569            try {
    570                classes.add(Class.forName(className));
    571            } catch (final Exception ex) {
    572                classes.add(null);
    573            }
    574        }
    575        return classes;
    576    }
    577
    578    /**
    579     * <p>Given a {@code List} of {@code Class} objects, this method converts
    580     * them into class names.</p>
    581     *
    582     * <p>A new {@code List} is returned. {@code null} objects will be copied into
    583     * the returned list as {@code null}.</p>
    584     *
    585     * @param classes  the classes to change
    586     * @return a {@code List} of class names corresponding to the Class objects,
    587     *  {@code null} if null input
    588     * @throws ClassCastException if {@code classes} contains a non-{@code Class} entry
    589     */
    590    public static List<String> convertClassesToClassNames(final List<Class<?>> classes) {
    591        if (classes == null) {
    592            return null;
    593        }
    594        final List<String> classNames = new ArrayList<>(classes.size());
    595        for (final Class<?> cls : classes) {
    596            if (cls == null) {
    597                classNames.add(null);
    598            } else {
    599                classNames.add(cls.getName());
    600            }
    601        }
    602        return classNames;
    603    }
    604
    605    // Is assignable
    606    // ----------------------------------------------------------------------
    607    /**
    608     * <p>Checks if an array of Classes can be assigned to another array of Classes.</p>
    609     *
    610     * <p>This method calls {@link #isAssignable(Class, Class) isAssignable} for each
    611     * Class pair in the input arrays. It can be used to check if a set of arguments
    612     * (the first parameter) are suitably compatible with a set of method parameter types
    613     * (the second parameter).</p>
    614     *
    615     * <p>Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, this
    616     * method takes into account widenings of primitive classes and
    617     * {@code null}s.</p>
    618     *
    619     * <p>Primitive widenings allow an int to be assigned to a {@code long},
    620     * {@code float} or {@code double}. This method returns the correct
    621     * result for these cases.</p>
    622     *
    623     * <p>{@code Null} may be assigned to any reference type. This method will
    624     * return {@code true} if {@code null} is passed in and the toClass is
    625     * non-primitive.</p>
    626     *
    627     * <p>Specifically, this method tests whether the type represented by the
    628     * specified {@code Class} parameter can be converted to the type
    629     * represented by this {@code Class} object via an identity conversion
    630     * widening primitive or widening reference conversion. See
    631     * <em><a href="http://docs.oracle.com/javase/specs/">The Java Language Specification</a></em>,
    632     * sections 5.1.1, 5.1.2 and 5.1.4 for details.</p>
    633     *
    634     * <p><strong>Since Lang 3.0,</strong> this method will default behavior for
    635     * calculating assignability between primitive and wrapper types <em>corresponding
    636     * to the running Java version</em>; i.e. autoboxing will be the default
    637     * behavior in VMs running Java versions &gt; 1.5.</p>
    638     *
    639     * @param classArray  the array of Classes to check, may be {@code null}
    640     * @param toClassArray  the array of Classes to try to assign into, may be {@code null}
    641     * @return {@code true} if assignment possible
    642     */
    643    public static boolean isAssignable(final Class<?>[] classArray, final Class<?>... toClassArray) {
    644        return isAssignable(classArray, toClassArray, true);
    645    }
    646
    647    /**
    648     * <p>Checks if an array of Classes can be assigned to another array of Classes.</p>
    649     *
    650     * <p>This method calls {@link #isAssignable(Class, Class) isAssignable} for each
    651     * Class pair in the input arrays. It can be used to check if a set of arguments
    652     * (the first parameter) are suitably compatible with a set of method parameter types
    653     * (the second parameter).</p>
    654     *
    655     * <p>Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, this
    656     * method takes into account widenings of primitive classes and
    657     * {@code null}s.</p>
    658     *
    659     * <p>Primitive widenings allow an int to be assigned to a {@code long},
    660     * {@code float} or {@code double}. This method returns the correct
    661     * result for these cases.</p>
    662     *
    663     * <p>{@code Null} may be assigned to any reference type. This method will
    664     * return {@code true} if {@code null} is passed in and the toClass is
    665     * non-primitive.</p>
    666     *
    667     * <p>Specifically, this method tests whether the type represented by the
    668     * specified {@code Class} parameter can be converted to the type
    669     * represented by this {@code Class} object via an identity conversion
    670     * widening primitive or widening reference conversion. See
    671     * <em><a href="http://docs.oracle.com/javase/specs/">The Java Language Specification</a></em>,
    672     * sections 5.1.1, 5.1.2 and 5.1.4 for details.</p>
    673     *
    674     * @param classArray  the array of Classes to check, may be {@code null}
    675     * @param toClassArray  the array of Classes to try to assign into, may be {@code null}
    676     * @param autoboxing  whether to use implicit autoboxing/unboxing between primitives and wrappers
    677     * @return {@code true} if assignment possible
    678     */
    679    public static boolean isAssignable(Class<?>[] classArray, Class<?>[] toClassArray, final boolean autoboxing) {
    680        if (!ArrayUtils.isSameLength(classArray, toClassArray)) {
    681            return false;
    682        }
    683        if (classArray == null) {
    684            classArray = ArrayUtils.EMPTY_CLASS_ARRAY;
    685        }
    686        if (toClassArray == null) {
    687            toClassArray = ArrayUtils.EMPTY_CLASS_ARRAY;
    688        }
    689        for (int i = 0; i < classArray.length; i++) {
    690            if (!isAssignable(classArray[i], toClassArray[i], autoboxing)) {
    691                return false;
    692            }
    693        }
    694        return true;
    695    }
    696
    697    /**
    698     * Returns whether the given {@code type} is a primitive or primitive wrapper ({@link Boolean}, {@link Byte}, {@link Character},
    699     * {@link Short}, {@link Integer}, {@link Long}, {@link Double}, {@link Float}).
    700     *
    701     * @param type
    702     *            The class to query or null.
    703     * @return true if the given {@code type} is a primitive or primitive wrapper ({@link Boolean}, {@link Byte}, {@link Character},
    704     *         {@link Short}, {@link Integer}, {@link Long}, {@link Double}, {@link Float}).
    705     * @since 3.1
    706     */
    707    public static boolean isPrimitiveOrWrapper(final Class<?> type) {
    708        if (type == null) {
    709            return false;
    710        }
    711        return type.isPrimitive() || isPrimitiveWrapper(type);
    712    }
    713
    714    /**
    715     * Returns whether the given {@code type} is a primitive wrapper ({@link Boolean}, {@link Byte}, {@link Character}, {@link Short},
    716     * {@link Integer}, {@link Long}, {@link Double}, {@link Float}).
    717     *
    718     * @param type
    719     *            The class to query or null.
    720     * @return true if the given {@code type} is a primitive wrapper ({@link Boolean}, {@link Byte}, {@link Character}, {@link Short},
    721     *         {@link Integer}, {@link Long}, {@link Double}, {@link Float}).
    722     * @since 3.1
    723     */
    724    public static boolean isPrimitiveWrapper(final Class<?> type) {
    725        return wrapperPrimitiveMap.containsKey(type);
    726    }
    727
    728    /**
    729     * <p>Checks if one {@code Class} can be assigned to a variable of
    730     * another {@code Class}.</p>
    731     *
    732     * <p>Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method,
    733     * this method takes into account widenings of primitive classes and
    734     * {@code null}s.</p>
    735     *
    736     * <p>Primitive widenings allow an int to be assigned to a long, float or
    737     * double. This method returns the correct result for these cases.</p>
    738     *
    739     * <p>{@code Null} may be assigned to any reference type. This method
    740     * will return {@code true} if {@code null} is passed in and the
    741     * toClass is non-primitive.</p>
    742     *
    743     * <p>Specifically, this method tests whether the type represented by the
    744     * specified {@code Class} parameter can be converted to the type
    745     * represented by this {@code Class} object via an identity conversion
    746     * widening primitive or widening reference conversion. See
    747     * <em><a href="http://docs.oracle.com/javase/specs/">The Java Language Specification</a></em>,
    748     * sections 5.1.1, 5.1.2 and 5.1.4 for details.</p>
    749     *
    750     * <p><strong>Since Lang 3.0,</strong> this method will default behavior for
    751     * calculating assignability between primitive and wrapper types <em>corresponding
    752     * to the running Java version</em>; i.e. autoboxing will be the default
    753     * behavior in VMs running Java versions &gt; 1.5.</p>
    754     *
    755     * @param cls  the Class to check, may be null
    756     * @param toClass  the Class to try to assign into, returns false if null
    757     * @return {@code true} if assignment possible
    758     */
    759    public static boolean isAssignable(final Class<?> cls, final Class<?> toClass) {
    760        return isAssignable(cls, toClass, true);
    761    }
    762
    763    /**
    764     * <p>Checks if one {@code Class} can be assigned to a variable of
    765     * another {@code Class}.</p>
    766     *
    767     * <p>Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method,
    768     * this method takes into account widenings of primitive classes and
    769     * {@code null}s.</p>
    770     *
    771     * <p>Primitive widenings allow an int to be assigned to a long, float or
    772     * double. This method returns the correct result for these cases.</p>
    773     *
    774     * <p>{@code Null} may be assigned to any reference type. This method
    775     * will return {@code true} if {@code null} is passed in and the
    776     * toClass is non-primitive.</p>
    777     *
    778     * <p>Specifically, this method tests whether the type represented by the
    779     * specified {@code Class} parameter can be converted to the type
    780     * represented by this {@code Class} object via an identity conversion
    781     * widening primitive or widening reference conversion. See
    782     * <em><a href="http://docs.oracle.com/javase/specs/">The Java Language Specification</a></em>,
    783     * sections 5.1.1, 5.1.2 and 5.1.4 for details.</p>
    784     *
    785     * @param cls  the Class to check, may be null
    786     * @param toClass  the Class to try to assign into, returns false if null
    787     * @param autoboxing  whether to use implicit autoboxing/unboxing between primitives and wrappers
    788     * @return {@code true} if assignment possible
    789     */
    790    public static boolean isAssignable(Class<?> cls, final Class<?> toClass, final boolean autoboxing) {
    791        if (toClass == null) {
    792            return false;
    793        }
    794        // have to check for null, as isAssignableFrom doesn't
    795        if (cls == null) {
    796            return !toClass.isPrimitive();
    797        }
    798        //autoboxing:
    799        if (autoboxing) {
    800            if (cls.isPrimitive() && !toClass.isPrimitive()) {
    801                cls = primitiveToWrapper(cls);
    802                if (cls == null) {
    803                    return false;
    804                }
    805            }
    806            if (toClass.isPrimitive() && !cls.isPrimitive()) {
    807                cls = wrapperToPrimitive(cls);
    808                if (cls == null) {
    809                    return false;
    810                }
    811            }
    812        }
    813        if (cls.equals(toClass)) {
    814            return true;
    815        }
    816        if (cls.isPrimitive()) {
    817            if (!toClass.isPrimitive()) {
    818                return false;
    819            }
    820            if (Integer.TYPE.equals(cls)) {
    821                return Long.TYPE.equals(toClass)
    822                    || Float.TYPE.equals(toClass)
    823                    || Double.TYPE.equals(toClass);
    824            }
    825            if (Long.TYPE.equals(cls)) {
    826                return Float.TYPE.equals(toClass)
    827                    || Double.TYPE.equals(toClass);
    828            }
    829            if (Boolean.TYPE.equals(cls)) {
    830                return false;
    831            }
    832            if (Double.TYPE.equals(cls)) {
    833                return false;
    834            }
    835            if (Float.TYPE.equals(cls)) {
    836                return Double.TYPE.equals(toClass);
    837            }
    838            if (Character.TYPE.equals(cls)) {
    839                return Integer.TYPE.equals(toClass)
    840                    || Long.TYPE.equals(toClass)
    841                    || Float.TYPE.equals(toClass)
    842                    || Double.TYPE.equals(toClass);
    843            }
    844            if (Short.TYPE.equals(cls)) {
    845                return Integer.TYPE.equals(toClass)
    846                    || Long.TYPE.equals(toClass)
    847                    || Float.TYPE.equals(toClass)
    848                    || Double.TYPE.equals(toClass);
    849            }
    850            if (Byte.TYPE.equals(cls)) {
    851                return Short.TYPE.equals(toClass)
    852                    || Integer.TYPE.equals(toClass)
    853                    || Long.TYPE.equals(toClass)
    854                    || Float.TYPE.equals(toClass)
    855                    || Double.TYPE.equals(toClass);
    856            }
    857            // should never get here
    858            return false;
    859        }
    860        return toClass.isAssignableFrom(cls);
    861    }
    862
    863    /**
    864     * <p>Converts the specified primitive Class object to its corresponding
    865     * wrapper Class object.</p>
    866     *
    867     * <p>NOTE: From v2.2, this method handles {@code Void.TYPE},
    868     * returning {@code Void.TYPE}.</p>
    869     *
    870     * @param cls  the class to convert, may be null
    871     * @return the wrapper class for {@code cls} or {@code cls} if
    872     * {@code cls} is not a primitive. {@code null} if null input.
    873     * @since 2.1
    874     */
    875    public static Class<?> primitiveToWrapper(final Class<?> cls) {
    876        Class<?> convertedClass = cls;
    877        if (cls != null && cls.isPrimitive()) {
    878            convertedClass = primitiveWrapperMap.get(cls);
    879        }
    880        return convertedClass;
    881    }
    882
    883    /**
    884     * <p>Converts the specified array of primitive Class objects to an array of
    885     * its corresponding wrapper Class objects.</p>
    886     *
    887     * @param classes  the class array to convert, may be null or empty
    888     * @return an array which contains for each given class, the wrapper class or
    889     * the original class if class is not a primitive. {@code null} if null input.
    890     * Empty array if an empty array passed in.
    891     * @since 2.1
    892     */
    893    public static Class<?>[] primitivesToWrappers(final Class<?>... classes) {
    894        if (classes == null) {
    895            return null;
    896        }
    897
    898        if (classes.length == 0) {
    899            return classes;
    900        }
    901
    902        final Class<?>[] convertedClasses = new Class[classes.length];
    903        for (int i = 0; i < classes.length; i++) {
    904            convertedClasses[i] = primitiveToWrapper(classes[i]);
    905        }
    906        return convertedClasses;
    907    }
    908
    909    /**
    910     * <p>Converts the specified wrapper class to its corresponding primitive
    911     * class.</p>
    912     *
    913     * <p>This method is the counter part of {@code primitiveToWrapper()}.
    914     * If the passed in class is a wrapper class for a primitive type, this
    915     * primitive type will be returned (e.g. {@code Integer.TYPE} for
    916     * {@code Integer.class}). For other classes, or if the parameter is
    917     * <b>null</b>, the return value is <b>null</b>.</p>
    918     *
    919     * @param cls the class to convert, may be <b>null</b>
    920     * @return the corresponding primitive type if {@code cls} is a
    921     * wrapper class, <b>null</b> otherwise
    922     * @see #primitiveToWrapper(Class)
    923     * @since 2.4
    924     */
    925    public static Class<?> wrapperToPrimitive(final Class<?> cls) {
    926        return wrapperPrimitiveMap.get(cls);
    927    }
    928
    929    /**
    930     * <p>Converts the specified array of wrapper Class objects to an array of
    931     * its corresponding primitive Class objects.</p>
    932     *
    933     * <p>This method invokes {@code wrapperToPrimitive()} for each element
    934     * of the passed in array.</p>
    935     *
    936     * @param classes  the class array to convert, may be null or empty
    937     * @return an array which contains for each given class, the primitive class or
    938     * <b>null</b> if the original class is not a wrapper class. {@code null} if null input.
    939     * Empty array if an empty array passed in.
    940     * @see #wrapperToPrimitive(Class)
    941     * @since 2.4
    942     */
    943    public static Class<?>[] wrappersToPrimitives(final Class<?>... classes) {
    944        if (classes == null) {
    945            return null;
    946        }
    947
    948        if (classes.length == 0) {
    949            return classes;
    950        }
    951
    952        final Class<?>[] convertedClasses = new Class[classes.length];
    953        for (int i = 0; i < classes.length; i++) {
    954            convertedClasses[i] = wrapperToPrimitive(classes[i]);
    955        }
    956        return convertedClasses;
    957    }
    958
    959    // Inner class
    960    // ----------------------------------------------------------------------
    961    /**
    962     * <p>Is the specified class an inner class or static nested class.</p>
    963     *
    964     * @param cls  the class to check, may be null
    965     * @return {@code true} if the class is an inner or static nested class,
    966     *  false if not or {@code null}
    967     */
    968    public static boolean isInnerClass(final Class<?> cls) {
    969        return cls != null && cls.getEnclosingClass() != null;
    970    }
    971
    972    // Class loading
    973    // ----------------------------------------------------------------------
    974    /**
    975     * Returns the class represented by {@code className} using the
    976     * {@code classLoader}.  This implementation supports the syntaxes
    977     * "{@code java.util.Map.Entry[]}", "{@code java.util.Map$Entry[]}",
    978     * "{@code [Ljava.util.Map.Entry;}", and "{@code [Ljava.util.Map$Entry;}".
    979     *
    980     * @param classLoader  the class loader to use to load the class
    981     * @param className  the class name
    982     * @param initialize  whether the class must be initialized
    983     * @return the class represented by {@code className} using the {@code classLoader}
    984     * @throws ClassNotFoundException if the class is not found
    985     */
    986    public static Class<?> getClass(
    987            final ClassLoader classLoader, final String className, final boolean initialize) throws ClassNotFoundException {
    988        try {
    989            Class<?> clazz;
    990            if (namePrimitiveMap.containsKey(className)) {
    991                clazz = namePrimitiveMap.get(className);
    992            } else {
    993                clazz = Class.forName(toCanonicalName(className), initialize, classLoader);
    994            }
    995            return clazz;
    996        } catch (final ClassNotFoundException ex) {
    997            // allow path separators (.) as inner class name separators
    998            final int lastDotIndex = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR);
    999
    1000            if (lastDotIndex != -1) {
    1001                try {
    1002                    return getClass(classLoader, className.substring(0, lastDotIndex) +
    1003                            INNER_CLASS_SEPARATOR_CHAR + className.substring(lastDotIndex + 1),
    1004                            initialize);
    1005                } catch (final ClassNotFoundException ex2) { // NOPMD
    1006                    // ignore exception
    1007                }
    1008            }
    1009
    1010            throw ex;
    1011        }
    1012    }
    1013
    1014    /**
    1015     * Returns the (initialized) class represented by {@code className}
    1016     * using the {@code classLoader}.  This implementation supports
    1017     * the syntaxes "{@code java.util.Map.Entry[]}",
    1018     * "{@code java.util.Map$Entry[]}", "{@code [Ljava.util.Map.Entry;}",
    1019     * and "{@code [Ljava.util.Map$Entry;}".
    1020     *
    1021     * @param classLoader  the class loader to use to load the class
    1022     * @param className  the class name
    1023     * @return the class represented by {@code className} using the {@code classLoader}
    1024     * @throws ClassNotFoundException if the class is not found
    1025     */
    1026    public static Class<?> getClass(final ClassLoader classLoader, final String className) throws ClassNotFoundException {
    1027        return getClass(classLoader, className, true);
    1028    }
    1029
    1030    /**
    1031     * Returns the (initialized) class represented by {@code className}
    1032     * using the current thread's context class loader. This implementation
    1033     * supports the syntaxes "{@code java.util.Map.Entry[]}",
    1034     * "{@code java.util.Map$Entry[]}", "{@code [Ljava.util.Map.Entry;}",
    1035     * and "{@code [Ljava.util.Map$Entry;}".
    1036     *
    1037     * @param className  the class name
    1038     * @return the class represented by {@code className} using the current thread's context class loader
    1039     * @throws ClassNotFoundException if the class is not found
    1040     */
    1041    public static Class<?> getClass(final String className) throws ClassNotFoundException {
    1042        return getClass(className, true);
    1043    }
    1044
    1045    /**
    1046     * Returns the class represented by {@code className} using the
    1047     * current thread's context class loader. This implementation supports the
    1048     * syntaxes "{@code java.util.Map.Entry[]}", "{@code java.util.Map$Entry[]}",
    1049     * "{@code [Ljava.util.Map.Entry;}", and "{@code [Ljava.util.Map$Entry;}".
    1050     *
    1051     * @param className  the class name
    1052     * @param initialize  whether the class must be initialized
    1053     * @return the class represented by {@code className} using the current thread's context class loader
    1054     * @throws ClassNotFoundException if the class is not found
    1055     */
    1056    public static Class<?> getClass(final String className, final boolean initialize) throws ClassNotFoundException {
    1057        final ClassLoader contextCL = Thread.currentThread().getContextClassLoader();
    1058        final ClassLoader loader = contextCL == null ? ClassUtils.class.getClassLoader() : contextCL;
    1059        return getClass(loader, className, initialize);
    1060    }
    1061
    1062    // Public method
    1063    // ----------------------------------------------------------------------
    1064    /**
    1065     * <p>Returns the desired Method much like {@code Class.getMethod}, however
    1066     * it ensures that the returned Method is from a public class or interface and not
    1067     * from an anonymous inner class. This means that the Method is invokable and
    1068     * doesn't fall foul of Java bug
    1069     * <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4071957">4071957</a>).</p>
    1070     *
    1071     *  <pre>
    1072     *  <code>Set set = Collections.unmodifiableSet(...);
    1073     *  Method method = ClassUtils.getPublicMethod(set.getClass(), "isEmpty",  new Class[0]);
    1074     *  Object result = method.invoke(set, new Object[]);</code>
    1075     *  </pre>
    1076     *
    1077     * @param cls  the class to check, not null
    1078     * @param methodName  the name of the method
    1079     * @param parameterTypes  the list of parameters
    1080     * @return the method
    1081     * @throws NullPointerException if the class is null
    1082     * @throws SecurityException if a security violation occurred
    1083     * @throws NoSuchMethodException if the method is not found in the given class
    1084     *  or if the method doesn't conform with the requirements
    1085     */
    1086    public static Method getPublicMethod(final Class<?> cls, final String methodName, final Class<?>... parameterTypes)
    1087            throws NoSuchMethodException {
    1088
    1089        final Method declaredMethod = cls.getMethod(methodName, parameterTypes);
    1090        if (Modifier.isPublic(declaredMethod.getDeclaringClass().getModifiers())) {
    1091            return declaredMethod;
    1092        }
    1093
    1094        final List<Class<?>> candidateClasses = new ArrayList<>();
    1095        candidateClasses.addAll(getAllInterfaces(cls));
    1096        candidateClasses.addAll(getAllSuperclasses(cls));
    1097
    1098        for (final Class<?> candidateClass : candidateClasses) {
    1099            if (!Modifier.isPublic(candidateClass.getModifiers())) {
    1100                continue;
    1101            }
    1102            Method candidateMethod;
    1103            try {
    1104                candidateMethod = candidateClass.getMethod(methodName, parameterTypes);
    1105            } catch (final NoSuchMethodException ex) {
    1106                continue;
    1107            }
    1108            if (Modifier.isPublic(candidateMethod.getDeclaringClass().getModifiers())) {
    1109                return candidateMethod;
    1110            }
    1111        }
    1112
    1113        throw new NoSuchMethodException("Can't find a public method for " +
    1114                methodName + " " + ArrayUtils.toString(parameterTypes));
    1115    }
    1116
    1117    // ----------------------------------------------------------------------
    1118    /**
    1119     * Converts a class name to a JLS style class name.
    1120     *
    1121     * @param className  the class name
    1122     * @return the converted name
    1123     */
    1124    private static String toCanonicalName(String className) {
    1125        className = StringUtils.deleteWhitespace(className);
    1126        Validate.notNull(className, "className must not be null.");
    1127        if (className.endsWith("[]")) {
    1128            final StringBuilder classNameBuffer = new StringBuilder();
    1129            while (className.endsWith("[]")) {
    1130                className = className.substring(0, className.length() - 2);
    1131                classNameBuffer.append("[");
    1132            }
    1133            final String abbreviation = abbreviationMap.get(className);
    1134            if (abbreviation != null) {
    1135                classNameBuffer.append(abbreviation);
    1136            } else {
    1137                classNameBuffer.append("L").append(className).append(";");
    1138            }
    1139            className = classNameBuffer.toString();
    1140        }
    1141        return className;
    1142    }
    1143
    1144    /**
    1145     * <p>Converts an array of {@code Object} in to an array of {@code Class} objects.
    1146     * If any of these objects is null, a null element will be inserted into the array.</p>
    1147     *
    1148     * <p>This method returns {@code null} for a {@code null} input array.</p>
    1149     *
    1150     * @param array an {@code Object} array
    1151     * @return a {@code Class} array, {@code null} if null array input
    1152     * @since 2.4
    1153     */
    1154    public static Class<?>[] toClass(final Object... array) {
    1155        if (array == null) {
    1156            return null;
    1157        } else if (array.length == 0) {
    1158            return ArrayUtils.EMPTY_CLASS_ARRAY;
    1159        }
    1160        final Class<?>[] classes = new Class[array.length];
    1161        for (int i = 0; i < array.length; i++) {
    1162            classes[i] = array[i] == null ? null : array[i].getClass();
    1163        }
    1164        return classes;
    1165    }
    1166
    1167    // Short canonical name
    1168    // ----------------------------------------------------------------------
    1169    /**
    1170     * <p>Gets the canonical name minus the package name for an {@code Object}.</p>
    1171     *
    1172     * @param object  the class to get the short name for, may be null
    1173     * @param valueIfNull  the value to return if null
    1174     * @return the canonical name of the object without the package name, or the null value
    1175     * @since 2.4
    1176     */
    1177    public static String getShortCanonicalName(final Object object, final String valueIfNull) {
    1178        if (object == null) {
    1179            return valueIfNull;
    1180        }
    1181        return getShortCanonicalName(object.getClass().getName());
    1182    }
    1183
    1184    /**
    1185     * <p>Gets the canonical class name for a {@code Class}.</p>
    1186     *
    1187     * @param cls the class for which to get the canonical class name; may be null
    1188     * @return the canonical name of the class, or the empty String
    1189     * @since 3.7
    1190     * @see Class#getCanonicalName()
    1191     */
    1192    public static String getCanonicalName(final Class<?> cls) {
    1193        return getCanonicalName(cls, StringUtils.EMPTY);
    1194    }
    1195
    1196    /**
    1197     * <p>Gets the canonical name for a {@code Class}.</p>
    1198     *
    1199     * @param cls the class for which to get the canonical class name; may be null
    1200     * @param valueIfNull  the return value if null
    1201     * @return the canonical name of the class, or {@code valueIfNull}
    1202     * @since 3.7
    1203     * @see Class#getCanonicalName()
    1204     */
    1205    public static String getCanonicalName(final Class<?> cls, final String valueIfNull) {
    1206        if (cls == null) {
    1207            return valueIfNull;
    1208        }
    1209        final String canonicalName = cls.getCanonicalName();
    1210        return canonicalName == null ? valueIfNull : canonicalName;
    1211    }
    1212
    1213    /**
    1214     * <p>Gets the canonical name for an {@code Object}.</p>
    1215     *
    1216     * @param object the object for which to get the canonical class name; may be null
    1217     * @return the canonical name of the object, or the empty String
    1218     * @since 3.7
    1219     * @see Class#getCanonicalName()
    1220     */
    1221    public static String getCanonicalName(final Object object) {
    1222        return getCanonicalName(object, StringUtils.EMPTY);
    1223    }
    1224
    1225    /**
    1226     * <p>Gets the canonical name for an {@code Object}.</p>
    1227     *
    1228     * @param object the object for which to get the canonical class name; may be null
    1229     * @param valueIfNull  the return value if null
    1230     * @return the canonical name of the object or {@code valueIfNull}
    1231     * @since 3.7
    1232     * @see Class#getCanonicalName()
    1233     */
    1234    public static String getCanonicalName(final Object object, final String valueIfNull) {
    1235        if (object == null) {
    1236            return valueIfNull;
    1237        }
    1238        final String canonicalName = object.getClass().getCanonicalName();
    1239        return canonicalName == null ? valueIfNull : canonicalName;
    1240    }
    1241
    1242    /**
    1243     * <p>Gets the canonical name minus the package name from a {@code Class}.</p>
    1244     *
    1245     * @param cls the class for which to get the short canonical class name; may be null
    1246     * @return the canonical name without the package name or an empty string
    1247     * @since 2.4
    1248     */
    1249    public static String getShortCanonicalName(final Class<?> cls) {
    1250        if (cls == null) {
    1251            return StringUtils.EMPTY;
    1252        }
    1253        return getShortCanonicalName(cls.getName());
    1254    }
    1255
    1256    /**
    1257     * <p>Gets the canonical name minus the package name from a String.</p>
    1258     *
    1259     * <p>The string passed in is assumed to be a canonical name - it is not checked.</p>
    1260     *
    1261     * @param canonicalName  the class name to get the short name for
    1262     * @return the canonical name of the class without the package name or an empty string
    1263     * @since 2.4
    1264     */
    1265    public static String getShortCanonicalName(final String canonicalName) {
    1266        return getShortClassName(getCanonicalName(canonicalName));
    1267    }
    1268
    1269    // Package name
    1270    // ----------------------------------------------------------------------
    1271    /**
    1272     * <p>Gets the package name from the canonical name of an {@code Object}.</p>
    1273     *
    1274     * @param object  the class to get the package name for, may be null
    1275     * @param valueIfNull  the value to return if null
    1276     * @return the package name of the object, or the null value
    1277     * @since 2.4
    1278     */
    1279    public static String getPackageCanonicalName(final Object object, final String valueIfNull) {
    1280        if (object == null) {
    1281            return valueIfNull;
    1282        }
    1283        return getPackageCanonicalName(object.getClass().getName());
    1284    }
    1285
    1286    /**
    1287     * <p>Gets the package name from the canonical name of a {@code Class}.</p>
    1288     *
    1289     * @param cls  the class to get the package name for, may be {@code null}.
    1290     * @return the package name or an empty string
    1291     * @since 2.4
    1292     */
    1293    public static String getPackageCanonicalName(final Class<?> cls) {
    1294        if (cls == null) {
    1295            return StringUtils.EMPTY;
    1296        }
    1297        return getPackageCanonicalName(cls.getName());
    1298    }
    1299
    1300    /**
    1301     * <p>Gets the package name from the canonical name. </p>
    1302     *
    1303     * <p>The string passed in is assumed to be a canonical name - it is not checked.</p>
    1304     * <p>If the class is unpackaged, return an empty string.</p>
    1305     *
    1306     * @param canonicalName  the canonical name to get the package name for, may be {@code null}
    1307     * @return the package name or an empty string
    1308     * @since 2.4
    1309     */
    1310    public static String getPackageCanonicalName(final String canonicalName) {
    1311        return getPackageName(getCanonicalName(canonicalName));
    1312    }
    1313
    1314    /**
    1315     * <p>Converts a given name of class into canonical format.
    1316     * If name of class is not a name of array class it returns
    1317     * unchanged name.</p>
    1318     * <p>Example:
    1319     * <ul>
    1320     * <li>{@code getCanonicalName("[I") = "int[]"}</li>
    1321     * <li>{@code getCanonicalName("[Ljava.lang.String;") = "java.lang.String[]"}</li>
    1322     * <li>{@code getCanonicalName("java.lang.String") = "java.lang.String"}</li>
    1323     * </ul>
    1324     * </p>
    1325     *
    1326     * @param className the name of class
    1327     * @return canonical form of class name
    1328     * @since 2.4
    1329     */
    1330    private static String getCanonicalName(String className) {
    1331        className = StringUtils.deleteWhitespace(className);
    1332        if (className == null) {
    1333            return null;
    1334        }
    1335        int dim = 0;
    1336        while (className.startsWith("[")) {
    1337            dim++;
    1338            className = className.substring(1);
    1339        }
    1340        if (dim < 1) {
    1341            return className;
    1342        }
    1343        if (className.startsWith("L")) {
    1344            className = className.substring(
    1345                1,
    1346                className.endsWith(";")
    1347                    ? className.length() - 1
    1348                    : className.length());
    1349        } else {
    1350            if (!className.isEmpty()) {
    1351                className = reverseAbbreviationMap.get(className.substring(0, 1));
    1352            }
    1353        }
    1354        final StringBuilder canonicalClassNameBuffer = new StringBuilder(className);
    1355        for (int i = 0; i < dim; i++) {
    1356            canonicalClassNameBuffer.append("[]");
    1357        }
    1358        return canonicalClassNameBuffer.toString();
    1359    }
    1360
    1361    /**
    1362     * Get an {@link Iterable} that can iterate over a class hierarchy in ascending (subclass to superclass) order,
    1363     * excluding interfaces.
    1364     *
    1365     * @param type the type to get the class hierarchy from
    1366     * @return Iterable an Iterable over the class hierarchy of the given class
    1367     * @since 3.2
    1368     */
    1369    public static Iterable<Class<?>> hierarchy(final Class<?> type) {
    1370        return hierarchy(type, Interfaces.EXCLUDE);
    1371    }
    1372
    1373    /**
    1374     * Get an {@link Iterable} that can iterate over a class hierarchy in ascending (subclass to superclass) order.
    1375     *
    1376     * @param type the type to get the class hierarchy from
    1377     * @param interfacesBehavior switch indicating whether to include or exclude interfaces
    1378     * @return Iterable an Iterable over the class hierarchy of the given class
    1379     * @since 3.2
    1380     */
    1381    public static Iterable<Class<?>> hierarchy(final Class<?> type, final Interfaces interfacesBehavior) {
    1382        final Iterable<Class<?>> classes = new Iterable<Class<?>>() {
    1383
    1384            @Override
    1385            public Iterator<Class<?>> iterator() {
    1386                final MutableObject<Class<?>> next = new MutableObject<Class<?>>(type);
    1387                return new Iterator<Class<?>>() {
    1388
    1389                    @Override
    1390                    public boolean hasNext() {
    1391                        return next.getValue() != null;
    1392                    }
    1393
    1394                    @Override
    1395                    public Class<?> next() {
    1396                        final Class<?> result = next.getValue();
    1397                        next.setValue(result.getSuperclass());
    1398                        return result;
    1399                    }
    1400
    1401                    @Override
    1402                    public void remove() {
    1403                        throw new UnsupportedOperationException();
    1404                    }
    1405
    1406                };
    1407            }
    1408
    1409        };
    1410        if (interfacesBehavior != Interfaces.INCLUDE) {
    1411            return classes;
    1412        }
    1413        return new Iterable<Class<?>>() {
    1414
    1415            @Override
    1416            public Iterator<Class<?>> iterator() {
    1417                final Set<Class<?>> seenInterfaces = new HashSet<>();
    1418                final Iterator<Class<?>> wrapped = classes.iterator();
    1419
    1420                return new Iterator<Class<?>>() {
    1421                    Iterator<Class<?>> interfaces = Collections.<Class<?>> emptySet().iterator();
    1422
    1423                    @Override
    1424                    public boolean hasNext() {
    1425                        return interfaces.hasNext() || wrapped.hasNext();
    1426                    }
    1427
    1428                    @Override
    1429                    public Class<?> next() {
    1430                        if (interfaces.hasNext()) {
    1431                            final Class<?> nextInterface = interfaces.next();
    1432                            seenInterfaces.add(nextInterface);
    1433                            return nextInterface;
    1434                        }
    1435                        final Class<?> nextSuperclass = wrapped.next();
    1436                        final Set<Class<?>> currentInterfaces = new LinkedHashSet<>();
    1437                        walkInterfaces(currentInterfaces, nextSuperclass);
    1438                        interfaces = currentInterfaces.iterator();
    1439                        return nextSuperclass;
    1440                    }
    1441
    1442                    private void walkInterfaces(final Set<Class<?>> addTo, final Class<?> c) {
    1443                        for (final Class<?> iface : c.getInterfaces()) {
    1444                            if (!seenInterfaces.contains(iface)) {
    1445                                addTo.add(iface);
    1446                            }
    1447                            walkInterfaces(addTo, iface);
    1448                        }
    1449                    }
    1450
    1451                    @Override
    1452                    public void remove() {
    1453                        throw new UnsupportedOperationException();
    1454                    }
    1455
    1456                };
    1457            }
    1458        };
    1459    }
    1460
    1461}