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