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