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