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