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 }