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