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 */ 017package org.apache.commons.lang3; 018 019import java.lang.reflect.Method; 020import java.lang.reflect.Modifier; 021import java.util.ArrayList; 022import java.util.Collections; 023import java.util.HashMap; 024import java.util.HashSet; 025import java.util.Iterator; 026import java.util.LinkedHashSet; 027import java.util.List; 028import java.util.Map; 029import java.util.Set; 030 031import org.apache.commons.lang3.mutable.MutableObject; 032 033/** 034 * <p>Operates on classes without using reflection.</p> 035 * 036 * <p>This class handles invalid {@code null} inputs as best it can. 037 * Each method documents its behaviour in more detail.</p> 038 * 039 * <p>The notion of a {@code canonical name} includes the human 040 * readable name for the type, for example {@code int[]}. The 041 * non-canonical method variants work with the JVM names, such as 042 * {@code [I}. </p> 043 * 044 * @since 2.0 045 */ 046public class ClassUtils { 047 048 /** 049 * Inclusivity literals for {@link #hierarchy(Class, Interfaces)}. 050 * @since 3.2 051 */ 052 public enum Interfaces { 053 INCLUDE, EXCLUDE 054 } 055 056 /** 057 * The package separator character: <code>'.' == {@value}</code>. 058 */ 059 public static final char PACKAGE_SEPARATOR_CHAR = '.'; 060 061 /** 062 * The package separator String: <code>"."</code>. 063 */ 064 public static final String PACKAGE_SEPARATOR = String.valueOf(PACKAGE_SEPARATOR_CHAR); 065 066 /** 067 * The inner class separator character: <code>'$' == {@value}</code>. 068 */ 069 public static final char INNER_CLASS_SEPARATOR_CHAR = '$'; 070 071 /** 072 * The inner class separator String: {@code "$"}. 073 */ 074 public static final String INNER_CLASS_SEPARATOR = String.valueOf(INNER_CLASS_SEPARATOR_CHAR); 075 076 /** 077 * Maps names of primitives to their corresponding primitive {@code Class}es. 078 */ 079 private static final Map<String, Class<?>> namePrimitiveMap = new HashMap<>(); 080 static { 081 namePrimitiveMap.put("boolean", Boolean.TYPE); 082 namePrimitiveMap.put("byte", Byte.TYPE); 083 namePrimitiveMap.put("char", Character.TYPE); 084 namePrimitiveMap.put("short", Short.TYPE); 085 namePrimitiveMap.put("int", Integer.TYPE); 086 namePrimitiveMap.put("long", Long.TYPE); 087 namePrimitiveMap.put("double", Double.TYPE); 088 namePrimitiveMap.put("float", Float.TYPE); 089 namePrimitiveMap.put("void", Void.TYPE); 090 } 091 092 /** 093 * Maps primitive {@code Class}es to their corresponding wrapper {@code Class}. 094 */ 095 private static final Map<Class<?>, Class<?>> primitiveWrapperMap = new HashMap<>(); 096 static { 097 primitiveWrapperMap.put(Boolean.TYPE, Boolean.class); 098 primitiveWrapperMap.put(Byte.TYPE, Byte.class); 099 primitiveWrapperMap.put(Character.TYPE, Character.class); 100 primitiveWrapperMap.put(Short.TYPE, Short.class); 101 primitiveWrapperMap.put(Integer.TYPE, Integer.class); 102 primitiveWrapperMap.put(Long.TYPE, Long.class); 103 primitiveWrapperMap.put(Double.TYPE, Double.class); 104 primitiveWrapperMap.put(Float.TYPE, Float.class); 105 primitiveWrapperMap.put(Void.TYPE, Void.TYPE); 106 } 107 108 /** 109 * Maps wrapper {@code Class}es to their corresponding primitive types. 110 */ 111 private static final Map<Class<?>, Class<?>> wrapperPrimitiveMap = new HashMap<>(); 112 static { 113 for (final Map.Entry<Class<?>, Class<?>> entry : primitiveWrapperMap.entrySet()) { 114 final Class<?> primitiveClass = entry.getKey(); 115 final Class<?> wrapperClass = entry.getValue(); 116 if (!primitiveClass.equals(wrapperClass)) { 117 wrapperPrimitiveMap.put(wrapperClass, primitiveClass); 118 } 119 } 120 } 121 122 /** 123 * Maps a primitive class name to its corresponding abbreviation used in array class names. 124 */ 125 private static final Map<String, String> abbreviationMap; 126 127 /** 128 * Maps an abbreviation used in array class names to corresponding primitive class name. 129 */ 130 private static final Map<String, String> reverseAbbreviationMap; 131 132 /** 133 * Feed abbreviation maps 134 */ 135 static { 136 final Map<String, String> m = new HashMap<>(); 137 m.put("int", "I"); 138 m.put("boolean", "Z"); 139 m.put("float", "F"); 140 m.put("long", "J"); 141 m.put("short", "S"); 142 m.put("byte", "B"); 143 m.put("double", "D"); 144 m.put("char", "C"); 145 final Map<String, String> r = new HashMap<>(); 146 for (final Map.Entry<String, String> e : m.entrySet()) { 147 r.put(e.getValue(), e.getKey()); 148 } 149 abbreviationMap = Collections.unmodifiableMap(m); 150 reverseAbbreviationMap = Collections.unmodifiableMap(r); 151 } 152 153 /** 154 * <p>ClassUtils instances should NOT be constructed in standard programming. 155 * Instead, the class should be used as 156 * {@code ClassUtils.getShortClassName(cls)}.</p> 157 * 158 * <p>This constructor is public to permit tools that require a JavaBean 159 * instance to operate.</p> 160 */ 161 public ClassUtils() { 162 super(); 163 } 164 165 // Short class name 166 // ---------------------------------------------------------------------- 167 /** 168 * <p>Gets the class name minus the package name for an {@code Object}.</p> 169 * 170 * @param object the class to get the short name for, may be null 171 * @param valueIfNull the value to return if null 172 * @return the class name of the object without the package name, or the null value 173 */ 174 public static String getShortClassName(final Object object, final String valueIfNull) { 175 if (object == null) { 176 return valueIfNull; 177 } 178 return getShortClassName(object.getClass()); 179 } 180 181 /** 182 * <p>Gets the class name minus the package name from a {@code Class}.</p> 183 * 184 * <p>Consider using the Java 5 API {@link Class#getSimpleName()} instead. 185 * The one known difference is that this code will return {@code "Map.Entry"} while 186 * the {@code java.lang.Class} variant will simply return {@code "Entry"}. </p> 187 * 188 * @param cls the class to get the short name for. 189 * @return the class name without the package name or an empty string 190 */ 191 public static String getShortClassName(final Class<?> cls) { 192 if (cls == null) { 193 return StringUtils.EMPTY; 194 } 195 return getShortClassName(cls.getName()); 196 } 197 198 /** 199 * <p>Gets the class name minus the package name from a String.</p> 200 * 201 * <p>The string passed in is assumed to be a class name - it is not checked.</p> 202 203 * <p>Note that this method differs from Class.getSimpleName() in that this will 204 * return {@code "Map.Entry"} whilst the {@code java.lang.Class} variant will simply 205 * return {@code "Entry"}. </p> 206 * 207 * @param className the className to get the short name for 208 * @return the class name of the class without the package name or an empty string 209 */ 210 public static String getShortClassName(String className) { 211 if (StringUtils.isEmpty(className)) { 212 return StringUtils.EMPTY; 213 } 214 215 final StringBuilder arrayPrefix = new StringBuilder(); 216 217 // Handle array encoding 218 if (className.startsWith("[")) { 219 while (className.charAt(0) == '[') { 220 className = className.substring(1); 221 arrayPrefix.append("[]"); 222 } 223 // Strip Object type encoding 224 if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';') { 225 className = className.substring(1, className.length() - 1); 226 } 227 228 if (reverseAbbreviationMap.containsKey(className)) { 229 className = reverseAbbreviationMap.get(className); 230 } 231 } 232 233 final int lastDotIdx = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR); 234 final int innerIdx = className.indexOf( 235 INNER_CLASS_SEPARATOR_CHAR, lastDotIdx == -1 ? 0 : lastDotIdx + 1); 236 String out = className.substring(lastDotIdx + 1); 237 if (innerIdx != -1) { 238 out = out.replace(INNER_CLASS_SEPARATOR_CHAR, PACKAGE_SEPARATOR_CHAR); 239 } 240 return out + arrayPrefix; 241 } 242 243 /** 244 * <p>Null-safe version of <code>aClass.getSimpleName()</code></p> 245 * 246 * @param cls the class for which to get the simple name; may be null 247 * @return the simple class name. 248 * @since 3.0 249 * @see Class#getSimpleName() 250 */ 251 public static String getSimpleName(final Class<?> cls) { 252 return getSimpleName(cls, StringUtils.EMPTY); 253 } 254 255 /** 256 * <p>Null-safe version of <code>aClass.getSimpleName()</code></p> 257 * 258 * @param cls the class for which to get the simple name; may be null 259 * @param valueIfNull the value to return if null 260 * @return the simple class name or {@code valueIfNull} 261 * @since 3.0 262 * @see Class#getSimpleName() 263 */ 264 public static String getSimpleName(final Class<?> cls, String valueIfNull) { 265 return cls == null ? valueIfNull : cls.getSimpleName(); 266 } 267 268 /** 269 * <p>Null-safe version of <code>aClass.getSimpleName()</code></p> 270 * 271 * @param object the object for which to get the simple class name; may be null 272 * @return the simple class name or the empty String 273 * @since 3.7 274 * @see Class#getSimpleName() 275 */ 276 public static String getSimpleName(final Object object) { 277 return getSimpleName(object, StringUtils.EMPTY); 278 } 279 280 /** 281 * <p>Null-safe version of <code>aClass.getSimpleName()</code></p> 282 * 283 * @param object the object for which to get the simple class name; may be null 284 * @param valueIfNull the value to return if <code>object</code> is <code>null</code> 285 * @return the simple class name or {@code valueIfNull} 286 * @since 3.0 287 * @see Class#getSimpleName() 288 */ 289 public static String getSimpleName(final Object object, final String valueIfNull) { 290 return object == null ? valueIfNull : object.getClass().getSimpleName(); 291 } 292 293 /** 294 * <p>Null-safe version of <code>Class.getName()</code></p> 295 * 296 * @param cls the class for which to get the class name; may be null 297 * @return the class name or the empty String. 298 * @since 3.7 299 * @see Class#getSimpleName() 300 */ 301 public static String getName(final Class<?> cls) { 302 return getName(cls, StringUtils.EMPTY); 303 } 304 305 /** 306 * <p>Null-safe version of <code>aClass.getName()</code></p> 307 * 308 * @param cls the class for which to get the class name; may be null 309 * @param valueIfNull the return value if <code>cls</code> is <code>null</code> 310 * @return the class name or {@code valueIfNull} 311 * @since 3.7 312 * @see Class#getName() 313 */ 314 public static String getName(final Class<?> cls, final String valueIfNull) { 315 return cls == null ? valueIfNull : cls.getName(); 316 } 317 318 /** 319 * <p>Null-safe version of <code>Class.getName()</code></p> 320 * 321 * @param object the object for which to get the class name; may be null 322 * @return the class name or the empty String 323 * @since 3.7 324 * @see Class#getSimpleName() 325 */ 326 public static String getName(final Object object) { 327 return getName(object, StringUtils.EMPTY); 328 } 329 330 /** 331 * <p>Null-safe version of <code>aClass.getSimpleName()</code></p> 332 * 333 * @param object the object for which to get the class name; may be null 334 * @param valueIfNull the value to return if <code>object</code> is <code>null</code> 335 * @return the class name or {@code valueIfNull} 336 * @since 3.0 337 * @see Class#getName() 338 */ 339 public static String getName(final Object object, final String valueIfNull) { 340 return object == null ? valueIfNull : object.getClass().getName(); 341 } 342 343 // Package name 344 // ---------------------------------------------------------------------- 345 /** 346 * <p>Gets the package name of an {@code Object}.</p> 347 * 348 * @param object the class to get the package name for, may be null 349 * @param valueIfNull the value to return if null 350 * @return the package name of the object, or the null value 351 */ 352 public static String getPackageName(final Object object, final String valueIfNull) { 353 if (object == null) { 354 return valueIfNull; 355 } 356 return getPackageName(object.getClass()); 357 } 358 359 /** 360 * <p>Gets the package name of a {@code Class}.</p> 361 * 362 * @param cls the class to get the package name for, may be {@code null}. 363 * @return the package name or an empty string 364 */ 365 public static String getPackageName(final Class<?> cls) { 366 if (cls == null) { 367 return StringUtils.EMPTY; 368 } 369 return getPackageName(cls.getName()); 370 } 371 372 /** 373 * <p>Gets the package name from a {@code String}.</p> 374 * 375 * <p>The string passed in is assumed to be a class name - it is not checked.</p> 376 * <p>If the class is unpackaged, return an empty string.</p> 377 * 378 * @param className the className to get the package name for, may be {@code null} 379 * @return the package name or an empty string 380 */ 381 public static String getPackageName(String className) { 382 if (StringUtils.isEmpty(className)) { 383 return StringUtils.EMPTY; 384 } 385 386 // Strip array encoding 387 while (className.charAt(0) == '[') { 388 className = className.substring(1); 389 } 390 // Strip Object type encoding 391 if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';') { 392 className = className.substring(1); 393 } 394 395 final int i = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR); 396 if (i == -1) { 397 return StringUtils.EMPTY; 398 } 399 return className.substring(0, i); 400 } 401 402 // Abbreviated name 403 // ---------------------------------------------------------------------- 404 /** 405 * <p>Gets the abbreviated name of a {@code Class}.</p> 406 * 407 * @param cls the class to get the abbreviated name for, may be {@code null} 408 * @param len the desired length of the abbreviated name 409 * @return the abbreviated name or an empty string 410 * @throws IllegalArgumentException if len <= 0 411 * @see #getAbbreviatedName(String, int) 412 * @since 3.4 413 */ 414 public static String getAbbreviatedName(final Class<?> cls, final int len) { 415 if (cls == null) { 416 return StringUtils.EMPTY; 417 } 418 return getAbbreviatedName(cls.getName(), len); 419 } 420 421 /** 422 * <p>Gets the abbreviated class name from a {@code String}.</p> 423 * 424 * <p>The string passed in is assumed to be a class name - it is not checked.</p> 425 * 426 * <p>The abbreviation algorithm will shorten the class name, usually without 427 * significant loss of meaning.</p> 428 * <p>The abbreviated class name will always include the complete package hierarchy. 429 * If enough space is available, rightmost sub-packages will be displayed in full 430 * length.</p> 431 * 432 * <table> 433 * <caption>Examples</caption> 434 * <tr><td>className</td><td>len</td><td>return</td></tr> 435 * <tr><td> null</td><td> 1</td><td>""</td></tr> 436 * <tr><td>"java.lang.String"</td><td> 5</td><td>"j.l.String"</td></tr> 437 * <tr><td>"java.lang.String"</td><td>15</td><td>"j.lang.String"</td></tr> 438 * <tr><td>"java.lang.String"</td><td>30</td><td>"java.lang.String"</td></tr> 439 * </table> 440 * @param className the className to get the abbreviated name for, may be {@code null} 441 * @param len the desired length of the abbreviated name 442 * @return the abbreviated name or an empty string 443 * @throws IllegalArgumentException if len <= 0 444 * @since 3.4 445 */ 446 public static String getAbbreviatedName(final String className, final int len) { 447 if (len <= 0) { 448 throw new IllegalArgumentException("len must be > 0"); 449 } 450 if (className == null) { 451 return StringUtils.EMPTY; 452 } 453 454 int availableSpace = len; 455 final int packageLevels = StringUtils.countMatches(className, '.'); 456 final String[] output = new String[packageLevels + 1]; 457 int endIndex = className.length() - 1; 458 for (int level = packageLevels; level >= 0; level--) { 459 final int startIndex = className.lastIndexOf('.', endIndex); 460 final String part = className.substring(startIndex + 1, endIndex + 1); 461 availableSpace -= part.length(); 462 if (level > 0) { 463 // all elements except top level require an additional char space 464 availableSpace--; 465 } 466 if (level == packageLevels) { 467 // ClassName is always complete 468 output[level] = part; 469 } else { 470 if (availableSpace > 0) { 471 output[level] = part; 472 } else { 473 // if no space is left still the first char is used 474 output[level] = part.substring(0, 1); 475 } 476 } 477 endIndex = startIndex - 1; 478 } 479 480 return StringUtils.join(output, '.'); 481 } 482 483 // Superclasses/Superinterfaces 484 // ---------------------------------------------------------------------- 485 /** 486 * <p>Gets a {@code List} of superclasses for the given class.</p> 487 * 488 * @param cls the class to look up, may be {@code null} 489 * @return the {@code List} of superclasses in order going up from this one 490 * {@code null} if null input 491 */ 492 public static List<Class<?>> getAllSuperclasses(final Class<?> cls) { 493 if (cls == null) { 494 return null; 495 } 496 final List<Class<?>> classes = new ArrayList<>(); 497 Class<?> superclass = cls.getSuperclass(); 498 while (superclass != null) { 499 classes.add(superclass); 500 superclass = superclass.getSuperclass(); 501 } 502 return classes; 503 } 504 505 /** 506 * <p>Gets a {@code List} of all interfaces implemented by the given 507 * class and its superclasses.</p> 508 * 509 * <p>The order is determined by looking through each interface in turn as 510 * declared in the source file and following its hierarchy up. Then each 511 * superclass is considered in the same way. Later duplicates are ignored, 512 * so the order is maintained.</p> 513 * 514 * @param cls the class to look up, may be {@code null} 515 * @return the {@code List} of interfaces in order, 516 * {@code null} if null input 517 */ 518 public static List<Class<?>> getAllInterfaces(final Class<?> cls) { 519 if (cls == null) { 520 return null; 521 } 522 523 final LinkedHashSet<Class<?>> interfacesFound = new LinkedHashSet<>(); 524 getAllInterfaces(cls, interfacesFound); 525 526 return new ArrayList<>(interfacesFound); 527 } 528 529 /** 530 * Get the interfaces for the specified class. 531 * 532 * @param cls the class to look up, may be {@code null} 533 * @param interfacesFound the {@code Set} of interfaces for the class 534 */ 535 private static void getAllInterfaces(Class<?> cls, final HashSet<Class<?>> interfacesFound) { 536 while (cls != null) { 537 final Class<?>[] interfaces = cls.getInterfaces(); 538 539 for (final Class<?> i : interfaces) { 540 if (interfacesFound.add(i)) { 541 getAllInterfaces(i, interfacesFound); 542 } 543 } 544 545 cls = cls.getSuperclass(); 546 } 547 } 548 549 // Convert list 550 // ---------------------------------------------------------------------- 551 /** 552 * <p>Given a {@code List} of class names, this method converts them into classes.</p> 553 * 554 * <p>A new {@code List} is returned. If the class name cannot be found, {@code null} 555 * is stored in the {@code List}. If the class name in the {@code List} is 556 * {@code null}, {@code null} is stored in the output {@code List}.</p> 557 * 558 * @param classNames the classNames to change 559 * @return a {@code List} of Class objects corresponding to the class names, 560 * {@code null} if null input 561 * @throws ClassCastException if classNames contains a non String entry 562 */ 563 public static List<Class<?>> convertClassNamesToClasses(final List<String> classNames) { 564 if (classNames == null) { 565 return null; 566 } 567 final List<Class<?>> classes = new ArrayList<>(classNames.size()); 568 for (final String className : classNames) { 569 try { 570 classes.add(Class.forName(className)); 571 } catch (final Exception ex) { 572 classes.add(null); 573 } 574 } 575 return classes; 576 } 577 578 /** 579 * <p>Given a {@code List} of {@code Class} objects, this method converts 580 * them into class names.</p> 581 * 582 * <p>A new {@code List} is returned. {@code null} objects will be copied into 583 * the returned list as {@code null}.</p> 584 * 585 * @param classes the classes to change 586 * @return a {@code List} of class names corresponding to the Class objects, 587 * {@code null} if null input 588 * @throws ClassCastException if {@code classes} contains a non-{@code Class} entry 589 */ 590 public static List<String> convertClassesToClassNames(final List<Class<?>> classes) { 591 if (classes == null) { 592 return null; 593 } 594 final List<String> classNames = new ArrayList<>(classes.size()); 595 for (final Class<?> cls : classes) { 596 if (cls == null) { 597 classNames.add(null); 598 } else { 599 classNames.add(cls.getName()); 600 } 601 } 602 return classNames; 603 } 604 605 // Is assignable 606 // ---------------------------------------------------------------------- 607 /** 608 * <p>Checks if an array of Classes can be assigned to another array of Classes.</p> 609 * 610 * <p>This method calls {@link #isAssignable(Class, Class) isAssignable} for each 611 * Class pair in the input arrays. It can be used to check if a set of arguments 612 * (the first parameter) are suitably compatible with a set of method parameter types 613 * (the second parameter).</p> 614 * 615 * <p>Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, this 616 * method takes into account widenings of primitive classes and 617 * {@code null}s.</p> 618 * 619 * <p>Primitive widenings allow an int to be assigned to a {@code long}, 620 * {@code float} or {@code double}. This method returns the correct 621 * result for these cases.</p> 622 * 623 * <p>{@code Null} may be assigned to any reference type. This method will 624 * return {@code true} if {@code null} is passed in and the toClass is 625 * non-primitive.</p> 626 * 627 * <p>Specifically, this method tests whether the type represented by the 628 * specified {@code Class} parameter can be converted to the type 629 * represented by this {@code Class} object via an identity conversion 630 * widening primitive or widening reference conversion. See 631 * <em><a href="http://docs.oracle.com/javase/specs/">The Java Language Specification</a></em>, 632 * sections 5.1.1, 5.1.2 and 5.1.4 for details.</p> 633 * 634 * <p><strong>Since Lang 3.0,</strong> this method will default behavior for 635 * calculating assignability between primitive and wrapper types <em>corresponding 636 * to the running Java version</em>; i.e. autoboxing will be the default 637 * behavior in VMs running Java versions > 1.5.</p> 638 * 639 * @param classArray the array of Classes to check, may be {@code null} 640 * @param toClassArray the array of Classes to try to assign into, may be {@code null} 641 * @return {@code true} if assignment possible 642 */ 643 public static boolean isAssignable(final Class<?>[] classArray, final Class<?>... toClassArray) { 644 return isAssignable(classArray, toClassArray, true); 645 } 646 647 /** 648 * <p>Checks if an array of Classes can be assigned to another array of Classes.</p> 649 * 650 * <p>This method calls {@link #isAssignable(Class, Class) isAssignable} for each 651 * Class pair in the input arrays. It can be used to check if a set of arguments 652 * (the first parameter) are suitably compatible with a set of method parameter types 653 * (the second parameter).</p> 654 * 655 * <p>Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, this 656 * method takes into account widenings of primitive classes and 657 * {@code null}s.</p> 658 * 659 * <p>Primitive widenings allow an int to be assigned to a {@code long}, 660 * {@code float} or {@code double}. This method returns the correct 661 * result for these cases.</p> 662 * 663 * <p>{@code Null} may be assigned to any reference type. This method will 664 * return {@code true} if {@code null} is passed in and the toClass is 665 * non-primitive.</p> 666 * 667 * <p>Specifically, this method tests whether the type represented by the 668 * specified {@code Class} parameter can be converted to the type 669 * represented by this {@code Class} object via an identity conversion 670 * widening primitive or widening reference conversion. See 671 * <em><a href="http://docs.oracle.com/javase/specs/">The Java Language Specification</a></em>, 672 * sections 5.1.1, 5.1.2 and 5.1.4 for details.</p> 673 * 674 * @param classArray the array of Classes to check, may be {@code null} 675 * @param toClassArray the array of Classes to try to assign into, may be {@code null} 676 * @param autoboxing whether to use implicit autoboxing/unboxing between primitives and wrappers 677 * @return {@code true} if assignment possible 678 */ 679 public static boolean isAssignable(Class<?>[] classArray, Class<?>[] toClassArray, final boolean autoboxing) { 680 if (!ArrayUtils.isSameLength(classArray, toClassArray)) { 681 return false; 682 } 683 if (classArray == null) { 684 classArray = ArrayUtils.EMPTY_CLASS_ARRAY; 685 } 686 if (toClassArray == null) { 687 toClassArray = ArrayUtils.EMPTY_CLASS_ARRAY; 688 } 689 for (int i = 0; i < classArray.length; i++) { 690 if (!isAssignable(classArray[i], toClassArray[i], autoboxing)) { 691 return false; 692 } 693 } 694 return true; 695 } 696 697 /** 698 * Returns whether the given {@code type} is a primitive or primitive wrapper ({@link Boolean}, {@link Byte}, {@link Character}, 699 * {@link Short}, {@link Integer}, {@link Long}, {@link Double}, {@link Float}). 700 * 701 * @param type 702 * The class to query or null. 703 * @return true if the given {@code type} is a primitive or primitive wrapper ({@link Boolean}, {@link Byte}, {@link Character}, 704 * {@link Short}, {@link Integer}, {@link Long}, {@link Double}, {@link Float}). 705 * @since 3.1 706 */ 707 public static boolean isPrimitiveOrWrapper(final Class<?> type) { 708 if (type == null) { 709 return false; 710 } 711 return type.isPrimitive() || isPrimitiveWrapper(type); 712 } 713 714 /** 715 * Returns whether the given {@code type} is a primitive wrapper ({@link Boolean}, {@link Byte}, {@link Character}, {@link Short}, 716 * {@link Integer}, {@link Long}, {@link Double}, {@link Float}). 717 * 718 * @param type 719 * The class to query or null. 720 * @return true if the given {@code type} is a primitive wrapper ({@link Boolean}, {@link Byte}, {@link Character}, {@link Short}, 721 * {@link Integer}, {@link Long}, {@link Double}, {@link Float}). 722 * @since 3.1 723 */ 724 public static boolean isPrimitiveWrapper(final Class<?> type) { 725 return wrapperPrimitiveMap.containsKey(type); 726 } 727 728 /** 729 * <p>Checks if one {@code Class} can be assigned to a variable of 730 * another {@code Class}.</p> 731 * 732 * <p>Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, 733 * this method takes into account widenings of primitive classes and 734 * {@code null}s.</p> 735 * 736 * <p>Primitive widenings allow an int to be assigned to a long, float or 737 * double. This method returns the correct result for these cases.</p> 738 * 739 * <p>{@code Null} may be assigned to any reference type. This method 740 * will return {@code true} if {@code null} is passed in and the 741 * toClass is non-primitive.</p> 742 * 743 * <p>Specifically, this method tests whether the type represented by the 744 * specified {@code Class} parameter can be converted to the type 745 * represented by this {@code Class} object via an identity conversion 746 * widening primitive or widening reference conversion. See 747 * <em><a href="http://docs.oracle.com/javase/specs/">The Java Language Specification</a></em>, 748 * sections 5.1.1, 5.1.2 and 5.1.4 for details.</p> 749 * 750 * <p><strong>Since Lang 3.0,</strong> this method will default behavior for 751 * calculating assignability between primitive and wrapper types <em>corresponding 752 * to the running Java version</em>; i.e. autoboxing will be the default 753 * behavior in VMs running Java versions > 1.5.</p> 754 * 755 * @param cls the Class to check, may be null 756 * @param toClass the Class to try to assign into, returns false if null 757 * @return {@code true} if assignment possible 758 */ 759 public static boolean isAssignable(final Class<?> cls, final Class<?> toClass) { 760 return isAssignable(cls, toClass, true); 761 } 762 763 /** 764 * <p>Checks if one {@code Class} can be assigned to a variable of 765 * another {@code Class}.</p> 766 * 767 * <p>Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, 768 * this method takes into account widenings of primitive classes and 769 * {@code null}s.</p> 770 * 771 * <p>Primitive widenings allow an int to be assigned to a long, float or 772 * double. This method returns the correct result for these cases.</p> 773 * 774 * <p>{@code Null} may be assigned to any reference type. This method 775 * will return {@code true} if {@code null} is passed in and the 776 * toClass is non-primitive.</p> 777 * 778 * <p>Specifically, this method tests whether the type represented by the 779 * specified {@code Class} parameter can be converted to the type 780 * represented by this {@code Class} object via an identity conversion 781 * widening primitive or widening reference conversion. See 782 * <em><a href="http://docs.oracle.com/javase/specs/">The Java Language Specification</a></em>, 783 * sections 5.1.1, 5.1.2 and 5.1.4 for details.</p> 784 * 785 * @param cls the Class to check, may be null 786 * @param toClass the Class to try to assign into, returns false if null 787 * @param autoboxing whether to use implicit autoboxing/unboxing between primitives and wrappers 788 * @return {@code true} if assignment possible 789 */ 790 public static boolean isAssignable(Class<?> cls, final Class<?> toClass, final boolean autoboxing) { 791 if (toClass == null) { 792 return false; 793 } 794 // have to check for null, as isAssignableFrom doesn't 795 if (cls == null) { 796 return !toClass.isPrimitive(); 797 } 798 //autoboxing: 799 if (autoboxing) { 800 if (cls.isPrimitive() && !toClass.isPrimitive()) { 801 cls = primitiveToWrapper(cls); 802 if (cls == null) { 803 return false; 804 } 805 } 806 if (toClass.isPrimitive() && !cls.isPrimitive()) { 807 cls = wrapperToPrimitive(cls); 808 if (cls == null) { 809 return false; 810 } 811 } 812 } 813 if (cls.equals(toClass)) { 814 return true; 815 } 816 if (cls.isPrimitive()) { 817 if (!toClass.isPrimitive()) { 818 return false; 819 } 820 if (Integer.TYPE.equals(cls)) { 821 return Long.TYPE.equals(toClass) 822 || Float.TYPE.equals(toClass) 823 || Double.TYPE.equals(toClass); 824 } 825 if (Long.TYPE.equals(cls)) { 826 return Float.TYPE.equals(toClass) 827 || Double.TYPE.equals(toClass); 828 } 829 if (Boolean.TYPE.equals(cls)) { 830 return false; 831 } 832 if (Double.TYPE.equals(cls)) { 833 return false; 834 } 835 if (Float.TYPE.equals(cls)) { 836 return Double.TYPE.equals(toClass); 837 } 838 if (Character.TYPE.equals(cls)) { 839 return Integer.TYPE.equals(toClass) 840 || Long.TYPE.equals(toClass) 841 || Float.TYPE.equals(toClass) 842 || Double.TYPE.equals(toClass); 843 } 844 if (Short.TYPE.equals(cls)) { 845 return Integer.TYPE.equals(toClass) 846 || Long.TYPE.equals(toClass) 847 || Float.TYPE.equals(toClass) 848 || Double.TYPE.equals(toClass); 849 } 850 if (Byte.TYPE.equals(cls)) { 851 return Short.TYPE.equals(toClass) 852 || Integer.TYPE.equals(toClass) 853 || Long.TYPE.equals(toClass) 854 || Float.TYPE.equals(toClass) 855 || Double.TYPE.equals(toClass); 856 } 857 // should never get here 858 return false; 859 } 860 return toClass.isAssignableFrom(cls); 861 } 862 863 /** 864 * <p>Converts the specified primitive Class object to its corresponding 865 * wrapper Class object.</p> 866 * 867 * <p>NOTE: From v2.2, this method handles {@code Void.TYPE}, 868 * returning {@code Void.TYPE}.</p> 869 * 870 * @param cls the class to convert, may be null 871 * @return the wrapper class for {@code cls} or {@code cls} if 872 * {@code cls} is not a primitive. {@code null} if null input. 873 * @since 2.1 874 */ 875 public static Class<?> primitiveToWrapper(final Class<?> cls) { 876 Class<?> convertedClass = cls; 877 if (cls != null && cls.isPrimitive()) { 878 convertedClass = primitiveWrapperMap.get(cls); 879 } 880 return convertedClass; 881 } 882 883 /** 884 * <p>Converts the specified array of primitive Class objects to an array of 885 * its corresponding wrapper Class objects.</p> 886 * 887 * @param classes the class array to convert, may be null or empty 888 * @return an array which contains for each given class, the wrapper class or 889 * the original class if class is not a primitive. {@code null} if null input. 890 * Empty array if an empty array passed in. 891 * @since 2.1 892 */ 893 public static Class<?>[] primitivesToWrappers(final Class<?>... classes) { 894 if (classes == null) { 895 return null; 896 } 897 898 if (classes.length == 0) { 899 return classes; 900 } 901 902 final Class<?>[] convertedClasses = new Class[classes.length]; 903 for (int i = 0; i < classes.length; i++) { 904 convertedClasses[i] = primitiveToWrapper(classes[i]); 905 } 906 return convertedClasses; 907 } 908 909 /** 910 * <p>Converts the specified wrapper class to its corresponding primitive 911 * class.</p> 912 * 913 * <p>This method is the counter part of {@code primitiveToWrapper()}. 914 * If the passed in class is a wrapper class for a primitive type, this 915 * primitive type will be returned (e.g. {@code Integer.TYPE} for 916 * {@code Integer.class}). For other classes, or if the parameter is 917 * <b>null</b>, the return value is <b>null</b>.</p> 918 * 919 * @param cls the class to convert, may be <b>null</b> 920 * @return the corresponding primitive type if {@code cls} is a 921 * wrapper class, <b>null</b> otherwise 922 * @see #primitiveToWrapper(Class) 923 * @since 2.4 924 */ 925 public static Class<?> wrapperToPrimitive(final Class<?> cls) { 926 return wrapperPrimitiveMap.get(cls); 927 } 928 929 /** 930 * <p>Converts the specified array of wrapper Class objects to an array of 931 * its corresponding primitive Class objects.</p> 932 * 933 * <p>This method invokes {@code wrapperToPrimitive()} for each element 934 * of the passed in array.</p> 935 * 936 * @param classes the class array to convert, may be null or empty 937 * @return an array which contains for each given class, the primitive class or 938 * <b>null</b> if the original class is not a wrapper class. {@code null} if null input. 939 * Empty array if an empty array passed in. 940 * @see #wrapperToPrimitive(Class) 941 * @since 2.4 942 */ 943 public static Class<?>[] wrappersToPrimitives(final Class<?>... classes) { 944 if (classes == null) { 945 return null; 946 } 947 948 if (classes.length == 0) { 949 return classes; 950 } 951 952 final Class<?>[] convertedClasses = new Class[classes.length]; 953 for (int i = 0; i < classes.length; i++) { 954 convertedClasses[i] = wrapperToPrimitive(classes[i]); 955 } 956 return convertedClasses; 957 } 958 959 // Inner class 960 // ---------------------------------------------------------------------- 961 /** 962 * <p>Is the specified class an inner class or static nested class.</p> 963 * 964 * @param cls the class to check, may be null 965 * @return {@code true} if the class is an inner or static nested class, 966 * false if not or {@code null} 967 */ 968 public static boolean isInnerClass(final Class<?> cls) { 969 return cls != null && cls.getEnclosingClass() != null; 970 } 971 972 // Class loading 973 // ---------------------------------------------------------------------- 974 /** 975 * Returns the class represented by {@code className} using the 976 * {@code classLoader}. This implementation supports the syntaxes 977 * "{@code java.util.Map.Entry[]}", "{@code java.util.Map$Entry[]}", 978 * "{@code [Ljava.util.Map.Entry;}", and "{@code [Ljava.util.Map$Entry;}". 979 * 980 * @param classLoader the class loader to use to load the class 981 * @param className the class name 982 * @param initialize whether the class must be initialized 983 * @return the class represented by {@code className} using the {@code classLoader} 984 * @throws ClassNotFoundException if the class is not found 985 */ 986 public static Class<?> getClass( 987 final ClassLoader classLoader, final String className, final boolean initialize) throws ClassNotFoundException { 988 try { 989 Class<?> clazz; 990 if (namePrimitiveMap.containsKey(className)) { 991 clazz = namePrimitiveMap.get(className); 992 } else { 993 clazz = Class.forName(toCanonicalName(className), initialize, classLoader); 994 } 995 return clazz; 996 } catch (final ClassNotFoundException ex) { 997 // allow path separators (.) as inner class name separators 998 final int lastDotIndex = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR); 999 1000 if (lastDotIndex != -1) { 1001 try { 1002 return getClass(classLoader, className.substring(0, lastDotIndex) + 1003 INNER_CLASS_SEPARATOR_CHAR + className.substring(lastDotIndex + 1), 1004 initialize); 1005 } catch (final ClassNotFoundException ex2) { // NOPMD 1006 // ignore exception 1007 } 1008 } 1009 1010 throw ex; 1011 } 1012 } 1013 1014 /** 1015 * Returns the (initialized) class represented by {@code className} 1016 * using the {@code classLoader}. This implementation supports 1017 * the syntaxes "{@code java.util.Map.Entry[]}", 1018 * "{@code java.util.Map$Entry[]}", "{@code [Ljava.util.Map.Entry;}", 1019 * and "{@code [Ljava.util.Map$Entry;}". 1020 * 1021 * @param classLoader the class loader to use to load the class 1022 * @param className the class name 1023 * @return the class represented by {@code className} using the {@code classLoader} 1024 * @throws ClassNotFoundException if the class is not found 1025 */ 1026 public static Class<?> getClass(final ClassLoader classLoader, final String className) throws ClassNotFoundException { 1027 return getClass(classLoader, className, true); 1028 } 1029 1030 /** 1031 * Returns the (initialized) class represented by {@code className} 1032 * using the current thread's context class loader. This implementation 1033 * supports the syntaxes "{@code java.util.Map.Entry[]}", 1034 * "{@code java.util.Map$Entry[]}", "{@code [Ljava.util.Map.Entry;}", 1035 * and "{@code [Ljava.util.Map$Entry;}". 1036 * 1037 * @param className the class name 1038 * @return the class represented by {@code className} using the current thread's context class loader 1039 * @throws ClassNotFoundException if the class is not found 1040 */ 1041 public static Class<?> getClass(final String className) throws ClassNotFoundException { 1042 return getClass(className, true); 1043 } 1044 1045 /** 1046 * Returns the class represented by {@code className} using the 1047 * current thread's context class loader. This implementation supports the 1048 * syntaxes "{@code java.util.Map.Entry[]}", "{@code java.util.Map$Entry[]}", 1049 * "{@code [Ljava.util.Map.Entry;}", and "{@code [Ljava.util.Map$Entry;}". 1050 * 1051 * @param className the class name 1052 * @param initialize whether the class must be initialized 1053 * @return the class represented by {@code className} using the current thread's context class loader 1054 * @throws ClassNotFoundException if the class is not found 1055 */ 1056 public static Class<?> getClass(final String className, final boolean initialize) throws ClassNotFoundException { 1057 final ClassLoader contextCL = Thread.currentThread().getContextClassLoader(); 1058 final ClassLoader loader = contextCL == null ? ClassUtils.class.getClassLoader() : contextCL; 1059 return getClass(loader, className, initialize); 1060 } 1061 1062 // Public method 1063 // ---------------------------------------------------------------------- 1064 /** 1065 * <p>Returns the desired Method much like {@code Class.getMethod}, however 1066 * it ensures that the returned Method is from a public class or interface and not 1067 * from an anonymous inner class. This means that the Method is invokable and 1068 * doesn't fall foul of Java bug 1069 * <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4071957">4071957</a>).</p> 1070 * 1071 * <pre> 1072 * <code>Set set = Collections.unmodifiableSet(...); 1073 * Method method = ClassUtils.getPublicMethod(set.getClass(), "isEmpty", new Class[0]); 1074 * Object result = method.invoke(set, new Object[]);</code> 1075 * </pre> 1076 * 1077 * @param cls the class to check, not null 1078 * @param methodName the name of the method 1079 * @param parameterTypes the list of parameters 1080 * @return the method 1081 * @throws NullPointerException if the class is null 1082 * @throws SecurityException if a security violation occurred 1083 * @throws NoSuchMethodException if the method is not found in the given class 1084 * or if the method doesn't conform with the requirements 1085 */ 1086 public static Method getPublicMethod(final Class<?> cls, final String methodName, final Class<?>... parameterTypes) 1087 throws NoSuchMethodException { 1088 1089 final Method declaredMethod = cls.getMethod(methodName, parameterTypes); 1090 if (Modifier.isPublic(declaredMethod.getDeclaringClass().getModifiers())) { 1091 return declaredMethod; 1092 } 1093 1094 final List<Class<?>> candidateClasses = new ArrayList<>(); 1095 candidateClasses.addAll(getAllInterfaces(cls)); 1096 candidateClasses.addAll(getAllSuperclasses(cls)); 1097 1098 for (final Class<?> candidateClass : candidateClasses) { 1099 if (!Modifier.isPublic(candidateClass.getModifiers())) { 1100 continue; 1101 } 1102 Method candidateMethod; 1103 try { 1104 candidateMethod = candidateClass.getMethod(methodName, parameterTypes); 1105 } catch (final NoSuchMethodException ex) { 1106 continue; 1107 } 1108 if (Modifier.isPublic(candidateMethod.getDeclaringClass().getModifiers())) { 1109 return candidateMethod; 1110 } 1111 } 1112 1113 throw new NoSuchMethodException("Can't find a public method for " + 1114 methodName + " " + ArrayUtils.toString(parameterTypes)); 1115 } 1116 1117 // ---------------------------------------------------------------------- 1118 /** 1119 * Converts a class name to a JLS style class name. 1120 * 1121 * @param className the class name 1122 * @return the converted name 1123 */ 1124 private static String toCanonicalName(String className) { 1125 className = StringUtils.deleteWhitespace(className); 1126 Validate.notNull(className, "className must not be null."); 1127 if (className.endsWith("[]")) { 1128 final StringBuilder classNameBuffer = new StringBuilder(); 1129 while (className.endsWith("[]")) { 1130 className = className.substring(0, className.length() - 2); 1131 classNameBuffer.append("["); 1132 } 1133 final String abbreviation = abbreviationMap.get(className); 1134 if (abbreviation != null) { 1135 classNameBuffer.append(abbreviation); 1136 } else { 1137 classNameBuffer.append("L").append(className).append(";"); 1138 } 1139 className = classNameBuffer.toString(); 1140 } 1141 return className; 1142 } 1143 1144 /** 1145 * <p>Converts an array of {@code Object} in to an array of {@code Class} objects. 1146 * If any of these objects is null, a null element will be inserted into the array.</p> 1147 * 1148 * <p>This method returns {@code null} for a {@code null} input array.</p> 1149 * 1150 * @param array an {@code Object} array 1151 * @return a {@code Class} array, {@code null} if null array input 1152 * @since 2.4 1153 */ 1154 public static Class<?>[] toClass(final Object... array) { 1155 if (array == null) { 1156 return null; 1157 } else if (array.length == 0) { 1158 return ArrayUtils.EMPTY_CLASS_ARRAY; 1159 } 1160 final Class<?>[] classes = new Class[array.length]; 1161 for (int i = 0; i < array.length; i++) { 1162 classes[i] = array[i] == null ? null : array[i].getClass(); 1163 } 1164 return classes; 1165 } 1166 1167 // Short canonical name 1168 // ---------------------------------------------------------------------- 1169 /** 1170 * <p>Gets the canonical name minus the package name for an {@code Object}.</p> 1171 * 1172 * @param object the class to get the short name for, may be null 1173 * @param valueIfNull the value to return if null 1174 * @return the canonical name of the object without the package name, or the null value 1175 * @since 2.4 1176 */ 1177 public static String getShortCanonicalName(final Object object, final String valueIfNull) { 1178 if (object == null) { 1179 return valueIfNull; 1180 } 1181 return getShortCanonicalName(object.getClass().getName()); 1182 } 1183 1184 /** 1185 * <p>Gets the canonical class name for a {@code Class}.</p> 1186 * 1187 * @param cls the class for which to get the canonical class name; may be null 1188 * @return the canonical name of the class, or the empty String 1189 * @since 3.7 1190 * @see Class#getCanonicalName() 1191 */ 1192 public static String getCanonicalName(final Class<?> cls) { 1193 return getCanonicalName(cls, StringUtils.EMPTY); 1194 } 1195 1196 /** 1197 * <p>Gets the canonical name for a {@code Class}.</p> 1198 * 1199 * @param cls the class for which to get the canonical class name; may be null 1200 * @param valueIfNull the return value if null 1201 * @return the canonical name of the class, or {@code valueIfNull} 1202 * @since 3.7 1203 * @see Class#getCanonicalName() 1204 */ 1205 public static String getCanonicalName(final Class<?> cls, final String valueIfNull) { 1206 if (cls == null) { 1207 return valueIfNull; 1208 } 1209 final String canonicalName = cls.getCanonicalName(); 1210 return canonicalName == null ? valueIfNull : canonicalName; 1211 } 1212 1213 /** 1214 * <p>Gets the canonical name for an {@code Object}.</p> 1215 * 1216 * @param object the object for which to get the canonical class name; may be null 1217 * @return the canonical name of the object, or the empty String 1218 * @since 3.7 1219 * @see Class#getCanonicalName() 1220 */ 1221 public static String getCanonicalName(final Object object) { 1222 return getCanonicalName(object, StringUtils.EMPTY); 1223 } 1224 1225 /** 1226 * <p>Gets the canonical name for an {@code Object}.</p> 1227 * 1228 * @param object the object for which to get the canonical class name; may be null 1229 * @param valueIfNull the return value if null 1230 * @return the canonical name of the object or {@code valueIfNull} 1231 * @since 3.7 1232 * @see Class#getCanonicalName() 1233 */ 1234 public static String getCanonicalName(final Object object, final String valueIfNull) { 1235 if (object == null) { 1236 return valueIfNull; 1237 } 1238 final String canonicalName = object.getClass().getCanonicalName(); 1239 return canonicalName == null ? valueIfNull : canonicalName; 1240 } 1241 1242 /** 1243 * <p>Gets the canonical name minus the package name from a {@code Class}.</p> 1244 * 1245 * @param cls the class for which to get the short canonical class name; may be null 1246 * @return the canonical name without the package name or an empty string 1247 * @since 2.4 1248 */ 1249 public static String getShortCanonicalName(final Class<?> cls) { 1250 if (cls == null) { 1251 return StringUtils.EMPTY; 1252 } 1253 return getShortCanonicalName(cls.getName()); 1254 } 1255 1256 /** 1257 * <p>Gets the canonical name minus the package name from a String.</p> 1258 * 1259 * <p>The string passed in is assumed to be a canonical name - it is not checked.</p> 1260 * 1261 * @param canonicalName the class name to get the short name for 1262 * @return the canonical name of the class without the package name or an empty string 1263 * @since 2.4 1264 */ 1265 public static String getShortCanonicalName(final String canonicalName) { 1266 return getShortClassName(getCanonicalName(canonicalName)); 1267 } 1268 1269 // Package name 1270 // ---------------------------------------------------------------------- 1271 /** 1272 * <p>Gets the package name from the canonical name of an {@code Object}.</p> 1273 * 1274 * @param object the class to get the package name for, may be null 1275 * @param valueIfNull the value to return if null 1276 * @return the package name of the object, or the null value 1277 * @since 2.4 1278 */ 1279 public static String getPackageCanonicalName(final Object object, final String valueIfNull) { 1280 if (object == null) { 1281 return valueIfNull; 1282 } 1283 return getPackageCanonicalName(object.getClass().getName()); 1284 } 1285 1286 /** 1287 * <p>Gets the package name from the canonical name of a {@code Class}.</p> 1288 * 1289 * @param cls the class to get the package name for, may be {@code null}. 1290 * @return the package name or an empty string 1291 * @since 2.4 1292 */ 1293 public static String getPackageCanonicalName(final Class<?> cls) { 1294 if (cls == null) { 1295 return StringUtils.EMPTY; 1296 } 1297 return getPackageCanonicalName(cls.getName()); 1298 } 1299 1300 /** 1301 * <p>Gets the package name from the canonical name. </p> 1302 * 1303 * <p>The string passed in is assumed to be a canonical name - it is not checked.</p> 1304 * <p>If the class is unpackaged, return an empty string.</p> 1305 * 1306 * @param canonicalName the canonical name to get the package name for, may be {@code null} 1307 * @return the package name or an empty string 1308 * @since 2.4 1309 */ 1310 public static String getPackageCanonicalName(final String canonicalName) { 1311 return getPackageName(getCanonicalName(canonicalName)); 1312 } 1313 1314 /** 1315 * <p>Converts a given name of class into canonical format. 1316 * If name of class is not a name of array class it returns 1317 * unchanged name.</p> 1318 * <p>Example: 1319 * <ul> 1320 * <li>{@code getCanonicalName("[I") = "int[]"}</li> 1321 * <li>{@code getCanonicalName("[Ljava.lang.String;") = "java.lang.String[]"}</li> 1322 * <li>{@code getCanonicalName("java.lang.String") = "java.lang.String"}</li> 1323 * </ul> 1324 * </p> 1325 * 1326 * @param className the name of class 1327 * @return canonical form of class name 1328 * @since 2.4 1329 */ 1330 private static String getCanonicalName(String className) { 1331 className = StringUtils.deleteWhitespace(className); 1332 if (className == null) { 1333 return null; 1334 } 1335 int dim = 0; 1336 while (className.startsWith("[")) { 1337 dim++; 1338 className = className.substring(1); 1339 } 1340 if (dim < 1) { 1341 return className; 1342 } 1343 if (className.startsWith("L")) { 1344 className = className.substring( 1345 1, 1346 className.endsWith(";") 1347 ? className.length() - 1 1348 : className.length()); 1349 } else { 1350 if (!className.isEmpty()) { 1351 className = reverseAbbreviationMap.get(className.substring(0, 1)); 1352 } 1353 } 1354 final StringBuilder canonicalClassNameBuffer = new StringBuilder(className); 1355 for (int i = 0; i < dim; i++) { 1356 canonicalClassNameBuffer.append("[]"); 1357 } 1358 return canonicalClassNameBuffer.toString(); 1359 } 1360 1361 /** 1362 * Get an {@link Iterable} that can iterate over a class hierarchy in ascending (subclass to superclass) order, 1363 * excluding interfaces. 1364 * 1365 * @param type the type to get the class hierarchy from 1366 * @return Iterable an Iterable over the class hierarchy of the given class 1367 * @since 3.2 1368 */ 1369 public static Iterable<Class<?>> hierarchy(final Class<?> type) { 1370 return hierarchy(type, Interfaces.EXCLUDE); 1371 } 1372 1373 /** 1374 * Get an {@link Iterable} that can iterate over a class hierarchy in ascending (subclass to superclass) order. 1375 * 1376 * @param type the type to get the class hierarchy from 1377 * @param interfacesBehavior switch indicating whether to include or exclude interfaces 1378 * @return Iterable an Iterable over the class hierarchy of the given class 1379 * @since 3.2 1380 */ 1381 public static Iterable<Class<?>> hierarchy(final Class<?> type, final Interfaces interfacesBehavior) { 1382 final Iterable<Class<?>> classes = new Iterable<Class<?>>() { 1383 1384 @Override 1385 public Iterator<Class<?>> iterator() { 1386 final MutableObject<Class<?>> next = new MutableObject<Class<?>>(type); 1387 return new Iterator<Class<?>>() { 1388 1389 @Override 1390 public boolean hasNext() { 1391 return next.getValue() != null; 1392 } 1393 1394 @Override 1395 public Class<?> next() { 1396 final Class<?> result = next.getValue(); 1397 next.setValue(result.getSuperclass()); 1398 return result; 1399 } 1400 1401 @Override 1402 public void remove() { 1403 throw new UnsupportedOperationException(); 1404 } 1405 1406 }; 1407 } 1408 1409 }; 1410 if (interfacesBehavior != Interfaces.INCLUDE) { 1411 return classes; 1412 } 1413 return new Iterable<Class<?>>() { 1414 1415 @Override 1416 public Iterator<Class<?>> iterator() { 1417 final Set<Class<?>> seenInterfaces = new HashSet<>(); 1418 final Iterator<Class<?>> wrapped = classes.iterator(); 1419 1420 return new Iterator<Class<?>>() { 1421 Iterator<Class<?>> interfaces = Collections.<Class<?>> emptySet().iterator(); 1422 1423 @Override 1424 public boolean hasNext() { 1425 return interfaces.hasNext() || wrapped.hasNext(); 1426 } 1427 1428 @Override 1429 public Class<?> next() { 1430 if (interfaces.hasNext()) { 1431 final Class<?> nextInterface = interfaces.next(); 1432 seenInterfaces.add(nextInterface); 1433 return nextInterface; 1434 } 1435 final Class<?> nextSuperclass = wrapped.next(); 1436 final Set<Class<?>> currentInterfaces = new LinkedHashSet<>(); 1437 walkInterfaces(currentInterfaces, nextSuperclass); 1438 interfaces = currentInterfaces.iterator(); 1439 return nextSuperclass; 1440 } 1441 1442 private void walkInterfaces(final Set<Class<?>> addTo, final Class<?> c) { 1443 for (final Class<?> iface : c.getInterfaces()) { 1444 if (!seenInterfaces.contains(iface)) { 1445 addTo.add(iface); 1446 } 1447 walkInterfaces(addTo, iface); 1448 } 1449 } 1450 1451 @Override 1452 public void remove() { 1453 throw new UnsupportedOperationException(); 1454 } 1455 1456 }; 1457 } 1458 }; 1459 } 1460 1461}