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