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