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 behavior 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
054        /** Includes interfaces. */
055        INCLUDE,
056
057        /** Excludes interfaces. */
058        EXCLUDE
059    }
060
061    /**
062     * The package separator character: {@code '&#x2e;' == {@value}}.
063     */
064    public static final char PACKAGE_SEPARATOR_CHAR = '.';
065
066    /**
067     * The package separator String: {@code "&#x2e;"}.
068     */
069    public static final String PACKAGE_SEPARATOR = String.valueOf(PACKAGE_SEPARATOR_CHAR);
070
071    /**
072     * The inner class separator character: {@code '$' == {@value}}.
073     */
074    public static final char INNER_CLASS_SEPARATOR_CHAR = '$';
075
076    /**
077     * The inner class separator String: {@code "$"}.
078     */
079    public static final String INNER_CLASS_SEPARATOR = String.valueOf(INNER_CLASS_SEPARATOR_CHAR);
080
081    /**
082     * Maps names of primitives to their corresponding primitive {@code Class}es.
083     */
084    private static final Map<String, Class<?>> namePrimitiveMap = new HashMap<>();
085    static {
086         namePrimitiveMap.put("boolean", Boolean.TYPE);
087         namePrimitiveMap.put("byte", Byte.TYPE);
088         namePrimitiveMap.put("char", Character.TYPE);
089         namePrimitiveMap.put("short", Short.TYPE);
090         namePrimitiveMap.put("int", Integer.TYPE);
091         namePrimitiveMap.put("long", Long.TYPE);
092         namePrimitiveMap.put("double", Double.TYPE);
093         namePrimitiveMap.put("float", Float.TYPE);
094         namePrimitiveMap.put("void", Void.TYPE);
095    }
096
097    /**
098     * Maps primitive {@code Class}es to their corresponding wrapper {@code Class}.
099     */
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}