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}