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