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