001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.lang3; 018 019import java.lang.reflect.Method; 020import java.lang.reflect.Modifier; 021import java.util.ArrayList; 022import java.util.Arrays; 023import java.util.Collections; 024import java.util.Comparator; 025import java.util.HashMap; 026import java.util.HashSet; 027import java.util.Iterator; 028import java.util.LinkedHashSet; 029import java.util.List; 030import java.util.Map; 031import java.util.Objects; 032import java.util.Set; 033import java.util.stream.Collectors; 034 035import org.apache.commons.lang3.mutable.MutableObject; 036 037/** 038 * Operates on classes without using reflection. 039 * 040 * <p> 041 * This class handles invalid {@code null} inputs as best it can. Each method documents its behavior in more detail. 042 * </p> 043 * 044 * <p> 045 * The notion of a {@code canonical name} includes the human readable name for the type, for example {@code int[]}. The 046 * non-canonical method variants work with the JVM names, such as {@code [I}. 047 * </p> 048 * 049 * @since 2.0 050 */ 051public class ClassUtils { 052 053 /** 054 * Inclusivity literals for {@link #hierarchy(Class, Interfaces)}. 055 * 056 * @since 3.2 057 */ 058 public enum Interfaces { 059 060 /** Includes interfaces. */ 061 INCLUDE, 062 063 /** Excludes interfaces. */ 064 EXCLUDE 065 } 066 067 private static final Comparator<Class<?>> COMPARATOR = (o1, o2) -> Objects.compare(getName(o1), getName(o2), String::compareTo); 068 069 /** 070 * The package separator character: {@code '.' == {@value}}. 071 */ 072 public static final char PACKAGE_SEPARATOR_CHAR = '.'; 073 074 /** 075 * The package separator String: {@code "."}. 076 */ 077 public static final String PACKAGE_SEPARATOR = String.valueOf(PACKAGE_SEPARATOR_CHAR); 078 079 /** 080 * The inner class separator character: {@code '$' == {@value}}. 081 */ 082 public static final char INNER_CLASS_SEPARATOR_CHAR = '$'; 083 084 /** 085 * The inner class separator String: {@code "$"}. 086 */ 087 public static final String INNER_CLASS_SEPARATOR = String.valueOf(INNER_CLASS_SEPARATOR_CHAR); 088 089 /** 090 * Maps names of primitives to their corresponding primitive {@link Class}es. 091 */ 092 private static final Map<String, Class<?>> namePrimitiveMap = new HashMap<>(); 093 094 static { 095 namePrimitiveMap.put(Boolean.TYPE.getSimpleName(), Boolean.TYPE); 096 namePrimitiveMap.put(Byte.TYPE.getSimpleName(), Byte.TYPE); 097 namePrimitiveMap.put(Character.TYPE.getSimpleName(), Character.TYPE); 098 namePrimitiveMap.put(Double.TYPE.getSimpleName(), Double.TYPE); 099 namePrimitiveMap.put(Float.TYPE.getSimpleName(), Float.TYPE); 100 namePrimitiveMap.put(Integer.TYPE.getSimpleName(), Integer.TYPE); 101 namePrimitiveMap.put(Long.TYPE.getSimpleName(), Long.TYPE); 102 namePrimitiveMap.put(Short.TYPE.getSimpleName(), Short.TYPE); 103 namePrimitiveMap.put(Void.TYPE.getSimpleName(), 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 final Class<?> clazz = getPrimitiveClass(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 * Gets the primitive class for the given class name, for example "byte". 755 * 756 * @param className the primitive class for the given class name. 757 * @return the primitive class. 758 */ 759 static Class<?> getPrimitiveClass(final String className) { 760 return namePrimitiveMap.get(className); 761 } 762 763 /** 764 * Returns the desired Method much like {@code Class.getMethod}, however it ensures that the returned Method is from a 765 * public class or interface and not from an anonymous inner class. This means that the Method is invokable and doesn't 766 * fall foul of Java bug <a href="https://bugs.java.com/bugdatabase/view_bug.do?bug_id=4071957">4071957</a>). 767 * 768 * <pre> 769 * {@code Set set = Collections.unmodifiableSet(...); 770 * Method method = ClassUtils.getPublicMethod(set.getClass(), "isEmpty", new Class[0]); 771 * Object result = method.invoke(set, new Object[]);} 772 * </pre> 773 * 774 * @param cls the class to check, not null 775 * @param methodName the name of the method 776 * @param parameterTypes the list of parameters 777 * @return the method 778 * @throws NullPointerException if the class is null 779 * @throws SecurityException if a security violation occurred 780 * @throws NoSuchMethodException if the method is not found in the given class or if the method doesn't conform with the 781 * requirements 782 */ 783 public static Method getPublicMethod(final Class<?> cls, final String methodName, final Class<?>... parameterTypes) throws NoSuchMethodException { 784 785 final Method declaredMethod = cls.getMethod(methodName, parameterTypes); 786 if (isPublic(declaredMethod.getDeclaringClass())) { 787 return declaredMethod; 788 } 789 790 final List<Class<?>> candidateClasses = new ArrayList<>(getAllInterfaces(cls)); 791 candidateClasses.addAll(getAllSuperclasses(cls)); 792 793 for (final Class<?> candidateClass : candidateClasses) { 794 if (!isPublic(candidateClass)) { 795 continue; 796 } 797 final Method candidateMethod; 798 try { 799 candidateMethod = candidateClass.getMethod(methodName, parameterTypes); 800 } catch (final NoSuchMethodException ex) { 801 continue; 802 } 803 if (Modifier.isPublic(candidateMethod.getDeclaringClass().getModifiers())) { 804 return candidateMethod; 805 } 806 } 807 808 throw new NoSuchMethodException("Can't find a public method for " + methodName + " " + ArrayUtils.toString(parameterTypes)); 809 } 810 811 /** 812 * Gets the canonical name minus the package name from a {@link Class}. 813 * 814 * @param cls the class for which to get the short canonical class name; may be null 815 * @return the canonical name without the package name or an empty string 816 * @since 2.4 817 * @see Class#getCanonicalName() 818 */ 819 public static String getShortCanonicalName(final Class<?> cls) { 820 return cls == null ? StringUtils.EMPTY : getShortCanonicalName(cls.getCanonicalName()); 821 } 822 823 /** 824 * Gets the canonical name minus the package name for an {@link Object}. 825 * 826 * @param object the class to get the short name for, may be null 827 * @param valueIfNull the value to return if null 828 * @return the canonical name of the object without the package name, or the null value 829 * @since 2.4 830 * @see Class#getCanonicalName() 831 */ 832 public static String getShortCanonicalName(final Object object, final String valueIfNull) { 833 return object == null ? valueIfNull : getShortCanonicalName(object.getClass().getCanonicalName()); 834 } 835 836 /** 837 * Gets the canonical name minus the package name from a String. 838 * 839 * <p> 840 * The string passed in is assumed to be a class name - it is not checked. 841 * </p> 842 * 843 * <p> 844 * Note that this method is mainly designed to handle the arrays and primitives properly. If the class is an inner class 845 * then the result value will not contain the outer classes. This way the behavior of this method is different from 846 * {@link #getShortClassName(String)}. The argument in that case is class name and not canonical name and the return 847 * value retains the outer classes. 848 * </p> 849 * 850 * <p> 851 * Note that there is no way to reliably identify the part of the string representing the package hierarchy and the part 852 * that is the outer class or classes in case of an inner class. Trying to find the class would require reflective call 853 * and the class itself may not even be on the class path. Relying on the fact that class names start with capital 854 * letter and packages with lower case is heuristic. 855 * </p> 856 * 857 * <p> 858 * It is recommended to use {@link #getShortClassName(String)} for cases when the class is an inner class and use this 859 * method for cases it is designed for. 860 * </p> 861 * 862 * <table> 863 * <caption>Examples</caption> 864 * <tr> 865 * <td>return value</td> 866 * <td>input</td> 867 * </tr> 868 * <tr> 869 * <td>{@code ""}</td> 870 * <td>{@code (String)null}</td> 871 * </tr> 872 * <tr> 873 * <td>{@code "Map.Entry"}</td> 874 * <td>{@code java.util.Map.Entry.class.getName()}</td> 875 * </tr> 876 * <tr> 877 * <td>{@code "Entry"}</td> 878 * <td>{@code java.util.Map.Entry.class.getCanonicalName()}</td> 879 * </tr> 880 * <tr> 881 * <td>{@code "ClassUtils"}</td> 882 * <td>{@code "org.apache.commons.lang3.ClassUtils"}</td> 883 * </tr> 884 * <tr> 885 * <td>{@code "ClassUtils[]"}</td> 886 * <td>{@code "[Lorg.apache.commons.lang3.ClassUtils;"}</td> 887 * </tr> 888 * <tr> 889 * <td>{@code "ClassUtils[][]"}</td> 890 * <td>{@code "[[Lorg.apache.commons.lang3.ClassUtils;"}</td> 891 * </tr> 892 * <tr> 893 * <td>{@code "ClassUtils[]"}</td> 894 * <td>{@code "org.apache.commons.lang3.ClassUtils[]"}</td> 895 * </tr> 896 * <tr> 897 * <td>{@code "ClassUtils[][]"}</td> 898 * <td>{@code "org.apache.commons.lang3.ClassUtils[][]"}</td> 899 * </tr> 900 * <tr> 901 * <td>{@code "int[]"}</td> 902 * <td>{@code "[I"}</td> 903 * </tr> 904 * <tr> 905 * <td>{@code "int[]"}</td> 906 * <td>{@code int[].class.getCanonicalName()}</td> 907 * </tr> 908 * <tr> 909 * <td>{@code "int[]"}</td> 910 * <td>{@code int[].class.getName()}</td> 911 * </tr> 912 * <tr> 913 * <td>{@code "int[][]"}</td> 914 * <td>{@code "[[I"}</td> 915 * </tr> 916 * <tr> 917 * <td>{@code "int[]"}</td> 918 * <td>{@code "int[]"}</td> 919 * </tr> 920 * <tr> 921 * <td>{@code "int[][]"}</td> 922 * <td>{@code "int[][]"}</td> 923 * </tr> 924 * </table> 925 * 926 * @param canonicalName the class name to get the short name for 927 * @return the canonical name of the class without the package name or an empty string 928 * @since 2.4 929 */ 930 public static String getShortCanonicalName(final String canonicalName) { 931 return getShortClassName(getCanonicalName(canonicalName)); 932 } 933 934 /** 935 * Gets the class name minus the package name from a {@link Class}. 936 * 937 * <p> 938 * This method simply gets the name using {@code Class.getName()} and then calls {@link #getShortClassName(String)}. See 939 * relevant notes there. 940 * </p> 941 * 942 * @param cls the class to get the short name for. 943 * @return the class name without the package name or an empty string. If the class is an inner class then the returned 944 * value will contain the outer class or classes separated with {@code .} (dot) character. 945 */ 946 public static String getShortClassName(final Class<?> cls) { 947 if (cls == null) { 948 return StringUtils.EMPTY; 949 } 950 return getShortClassName(cls.getName()); 951 } 952 953 /** 954 * Gets the class name of the {@code object} without the package name or names. 955 * 956 * <p> 957 * The method looks up the class of the object and then converts the name of the class invoking 958 * {@link #getShortClassName(Class)} (see relevant notes there). 959 * </p> 960 * 961 * @param object the class to get the short name for, may be {@code null} 962 * @param valueIfNull the value to return if the object is {@code null} 963 * @return the class name of the object without the package name, or {@code valueIfNull} if the argument {@code object} 964 * is {@code null} 965 */ 966 public static String getShortClassName(final Object object, final String valueIfNull) { 967 if (object == null) { 968 return valueIfNull; 969 } 970 return getShortClassName(object.getClass()); 971 } 972 973 /** 974 * Gets the class name minus the package name from a String. 975 * 976 * <p> 977 * 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 978 * JDK method {@code Class.getName()} returns it, and not the usual way as we write it, for example in import 979 * statements, or as it is formatted by {@code Class.getCanonicalName()}. 980 * </p> 981 * 982 * <p> 983 * The difference is is significant only in case of classes that are inner classes of some other classes. In this case 984 * the separator between the outer and inner class (possibly on multiple hierarchy level) has to be {@code $} (dollar 985 * sign) and not {@code .} (dot), as it is returned by {@code Class.getName()} 986 * </p> 987 * 988 * <p> 989 * Note that this method is called from the {@link #getShortClassName(Class)} method using the string returned by 990 * {@code Class.getName()}. 991 * </p> 992 * 993 * <p> 994 * Note that this method differs from {@link #getSimpleName(Class)} in that this will return, for example 995 * {@code "Map.Entry"} whilst the {@link Class} variant will simply return {@code "Entry"}. In this example 996 * the argument {@code className} is the string {@code java.util.Map$Entry} (note the {@code $} sign. 997 * </p> 998 * 999 * @param className the className to get the short name for. It has to be formatted as returned by 1000 * {@code Class.getName()} and not {@code Class.getCanonicalName()} 1001 * @return the class name of the class without the package name or an empty string. If the class is an inner class then 1002 * value contains the outer class or classes and the separator is replaced to be {@code .} (dot) character. 1003 */ 1004 public static String getShortClassName(String className) { 1005 if (StringUtils.isEmpty(className)) { 1006 return StringUtils.EMPTY; 1007 } 1008 1009 final StringBuilder arrayPrefix = new StringBuilder(); 1010 1011 // Handle array encoding 1012 if (className.startsWith("[")) { 1013 while (className.charAt(0) == '[') { 1014 className = className.substring(1); 1015 arrayPrefix.append("[]"); 1016 } 1017 // Strip Object type encoding 1018 if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';') { 1019 className = className.substring(1, className.length() - 1); 1020 } 1021 1022 if (reverseAbbreviationMap.containsKey(className)) { 1023 className = reverseAbbreviationMap.get(className); 1024 } 1025 } 1026 1027 final int lastDotIdx = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR); 1028 final int innerIdx = className.indexOf(INNER_CLASS_SEPARATOR_CHAR, lastDotIdx == -1 ? 0 : lastDotIdx + 1); 1029 String out = className.substring(lastDotIdx + 1); 1030 if (innerIdx != -1) { 1031 out = out.replace(INNER_CLASS_SEPARATOR_CHAR, PACKAGE_SEPARATOR_CHAR); 1032 } 1033 return out + arrayPrefix; 1034 } 1035 1036 /** 1037 * Null-safe version of {@code cls.getSimpleName()} 1038 * 1039 * @param cls the class for which to get the simple name; may be null 1040 * @return the simple class name or the empty string in case the argument is {@code null} 1041 * @since 3.0 1042 * @see Class#getSimpleName() 1043 */ 1044 public static String getSimpleName(final Class<?> cls) { 1045 return getSimpleName(cls, StringUtils.EMPTY); 1046 } 1047 1048 /** 1049 * Null-safe version of {@code cls.getSimpleName()} 1050 * 1051 * @param cls the class for which to get the simple name; may be null 1052 * @param valueIfNull the value to return if null 1053 * @return the simple class name or {@code valueIfNull} if the argument {@code cls} is {@code null} 1054 * @since 3.0 1055 * @see Class#getSimpleName() 1056 */ 1057 public static String getSimpleName(final Class<?> cls, final String valueIfNull) { 1058 return cls == null ? valueIfNull : cls.getSimpleName(); 1059 } 1060 1061 /** 1062 * Null-safe version of {@code object.getClass().getSimpleName()} 1063 * 1064 * <p> 1065 * It is to note that this method is overloaded and in case the argument {@code object} is a {@link Class} object then 1066 * the {@link #getSimpleName(Class)} will be invoked. If this is a significant possibility then the caller should check 1067 * this case and call {@code 1068 * getSimpleName(Class.class)} or just simply use the string literal {@code "Class"}, which is the result of the method 1069 * in that case. 1070 * </p> 1071 * 1072 * @param object the object for which to get the simple class name; may be null 1073 * @return the simple class name or the empty string in case the argument is {@code null} 1074 * @since 3.7 1075 * @see Class#getSimpleName() 1076 */ 1077 public static String getSimpleName(final Object object) { 1078 return getSimpleName(object, StringUtils.EMPTY); 1079 } 1080 1081 /** 1082 * Null-safe version of {@code object.getClass().getSimpleName()} 1083 * 1084 * @param object the object for which to get the simple class name; may be null 1085 * @param valueIfNull the value to return if {@code object} is {@code null} 1086 * @return the simple class name or {@code valueIfNull} if the argument {@code object} is {@code null} 1087 * @since 3.0 1088 * @see Class#getSimpleName() 1089 */ 1090 public static String getSimpleName(final Object object, final String valueIfNull) { 1091 return object == null ? valueIfNull : object.getClass().getSimpleName(); 1092 } 1093 1094 /** 1095 * Gets an {@link Iterable} that can iterate over a class hierarchy in ascending (subclass to superclass) order, 1096 * excluding interfaces. 1097 * 1098 * @param type the type to get the class hierarchy from 1099 * @return Iterable an Iterable over the class hierarchy of the given class 1100 * @since 3.2 1101 */ 1102 public static Iterable<Class<?>> hierarchy(final Class<?> type) { 1103 return hierarchy(type, Interfaces.EXCLUDE); 1104 } 1105 1106 /** 1107 * Gets an {@link Iterable} that can iterate over a class hierarchy in ascending (subclass to superclass) order. 1108 * 1109 * @param type the type to get the class hierarchy from 1110 * @param interfacesBehavior switch indicating whether to include or exclude interfaces 1111 * @return Iterable an Iterable over the class hierarchy of the given class 1112 * @since 3.2 1113 */ 1114 public static Iterable<Class<?>> hierarchy(final Class<?> type, final Interfaces interfacesBehavior) { 1115 final Iterable<Class<?>> classes = () -> { 1116 final MutableObject<Class<?>> next = new MutableObject<>(type); 1117 return new Iterator<Class<?>>() { 1118 1119 @Override 1120 public boolean hasNext() { 1121 return next.getValue() != null; 1122 } 1123 1124 @Override 1125 public Class<?> next() { 1126 final Class<?> result = next.getValue(); 1127 next.setValue(result.getSuperclass()); 1128 return result; 1129 } 1130 1131 @Override 1132 public void remove() { 1133 throw new UnsupportedOperationException(); 1134 } 1135 1136 }; 1137 }; 1138 if (interfacesBehavior != Interfaces.INCLUDE) { 1139 return classes; 1140 } 1141 return () -> { 1142 final Set<Class<?>> seenInterfaces = new HashSet<>(); 1143 final Iterator<Class<?>> wrapped = classes.iterator(); 1144 1145 return new Iterator<Class<?>>() { 1146 Iterator<Class<?>> interfaces = Collections.emptyIterator(); 1147 1148 @Override 1149 public boolean hasNext() { 1150 return interfaces.hasNext() || wrapped.hasNext(); 1151 } 1152 1153 @Override 1154 public Class<?> next() { 1155 if (interfaces.hasNext()) { 1156 final Class<?> nextInterface = interfaces.next(); 1157 seenInterfaces.add(nextInterface); 1158 return nextInterface; 1159 } 1160 final Class<?> nextSuperclass = wrapped.next(); 1161 final Set<Class<?>> currentInterfaces = new LinkedHashSet<>(); 1162 walkInterfaces(currentInterfaces, nextSuperclass); 1163 interfaces = currentInterfaces.iterator(); 1164 return nextSuperclass; 1165 } 1166 1167 @Override 1168 public void remove() { 1169 throw new UnsupportedOperationException(); 1170 } 1171 1172 private void walkInterfaces(final Set<Class<?>> addTo, final Class<?> c) { 1173 for (final Class<?> iface : c.getInterfaces()) { 1174 if (!seenInterfaces.contains(iface)) { 1175 addTo.add(iface); 1176 } 1177 walkInterfaces(addTo, iface); 1178 } 1179 } 1180 1181 }; 1182 }; 1183 } 1184 1185 /** 1186 * Checks if one {@link Class} can be assigned to a variable of another {@link Class}. 1187 * 1188 * <p> 1189 * Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, this method takes into account widenings of 1190 * primitive classes and {@code null}s. 1191 * </p> 1192 * 1193 * <p> 1194 * Primitive widenings allow an int to be assigned to a long, float or double. This method returns the correct result 1195 * for these cases. 1196 * </p> 1197 * 1198 * <p> 1199 * {@code null} may be assigned to any reference type. This method will return {@code true} if {@code null} is passed in 1200 * and the toClass is non-primitive. 1201 * </p> 1202 * 1203 * <p> 1204 * Specifically, this method tests whether the type represented by the specified {@link Class} parameter can be 1205 * converted to the type represented by this {@link Class} object via an identity conversion widening primitive or 1206 * widening reference conversion. See <em><a href="https://docs.oracle.com/javase/specs/">The Java Language 1207 * Specification</a></em>, sections 5.1.1, 5.1.2 and 5.1.4 for details. 1208 * </p> 1209 * 1210 * <p> 1211 * <strong>Since Lang 3.0,</strong> this method will default behavior for calculating assignability between primitive 1212 * and wrapper types <em>corresponding to the running Java version</em>; i.e. autoboxing will be the default behavior in 1213 * VMs running Java versions > 1.5. 1214 * </p> 1215 * 1216 * @param cls the Class to check, may be null 1217 * @param toClass the Class to try to assign into, returns false if null 1218 * @return {@code true} if assignment possible 1219 */ 1220 public static boolean isAssignable(final Class<?> cls, final Class<?> toClass) { 1221 return isAssignable(cls, toClass, true); 1222 } 1223 1224 /** 1225 * Checks if one {@link Class} can be assigned to a variable of another {@link Class}. 1226 * 1227 * <p> 1228 * Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, this method takes into account widenings of 1229 * primitive classes and {@code null}s. 1230 * </p> 1231 * 1232 * <p> 1233 * Primitive widenings allow an int to be assigned to a long, float or double. This method returns the correct result 1234 * for these cases. 1235 * </p> 1236 * 1237 * <p> 1238 * {@code null} may be assigned to any reference type. This method will return {@code true} if {@code null} is passed in 1239 * and the toClass is non-primitive. 1240 * </p> 1241 * 1242 * <p> 1243 * Specifically, this method tests whether the type represented by the specified {@link Class} parameter can be 1244 * converted to the type represented by this {@link Class} object via an identity conversion widening primitive or 1245 * widening reference conversion. See <em><a href="https://docs.oracle.com/javase/specs/">The Java Language 1246 * Specification</a></em>, sections 5.1.1, 5.1.2 and 5.1.4 for details. 1247 * </p> 1248 * 1249 * @param cls the Class to check, may be null 1250 * @param toClass the Class to try to assign into, returns false if null 1251 * @param autoboxing whether to use implicit autoboxing/unboxing between primitives and wrappers 1252 * @return {@code true} if assignment possible 1253 */ 1254 public static boolean isAssignable(Class<?> cls, final Class<?> toClass, final boolean autoboxing) { 1255 if (toClass == null) { 1256 return false; 1257 } 1258 // have to check for null, as isAssignableFrom doesn't 1259 if (cls == null) { 1260 return !toClass.isPrimitive(); 1261 } 1262 // autoboxing: 1263 if (autoboxing) { 1264 if (cls.isPrimitive() && !toClass.isPrimitive()) { 1265 cls = primitiveToWrapper(cls); 1266 if (cls == null) { 1267 return false; 1268 } 1269 } 1270 if (toClass.isPrimitive() && !cls.isPrimitive()) { 1271 cls = wrapperToPrimitive(cls); 1272 if (cls == null) { 1273 return false; 1274 } 1275 } 1276 } 1277 if (cls.equals(toClass)) { 1278 return true; 1279 } 1280 if (cls.isPrimitive()) { 1281 if (!toClass.isPrimitive()) { 1282 return false; 1283 } 1284 if (Integer.TYPE.equals(cls)) { 1285 return Long.TYPE.equals(toClass) || Float.TYPE.equals(toClass) || Double.TYPE.equals(toClass); 1286 } 1287 if (Long.TYPE.equals(cls)) { 1288 return Float.TYPE.equals(toClass) || Double.TYPE.equals(toClass); 1289 } 1290 if (Boolean.TYPE.equals(cls)) { 1291 return false; 1292 } 1293 if (Double.TYPE.equals(cls)) { 1294 return false; 1295 } 1296 if (Float.TYPE.equals(cls)) { 1297 return Double.TYPE.equals(toClass); 1298 } 1299 if (Character.TYPE.equals(cls) || Short.TYPE.equals(cls)) { 1300 return Integer.TYPE.equals(toClass) || Long.TYPE.equals(toClass) || Float.TYPE.equals(toClass) || Double.TYPE.equals(toClass); 1301 } 1302 if (Byte.TYPE.equals(cls)) { 1303 return Short.TYPE.equals(toClass) || Integer.TYPE.equals(toClass) || Long.TYPE.equals(toClass) || Float.TYPE.equals(toClass) 1304 || Double.TYPE.equals(toClass); 1305 } 1306 // should never get here 1307 return false; 1308 } 1309 return toClass.isAssignableFrom(cls); 1310 } 1311 1312 /** 1313 * Checks if an array of Classes can be assigned to another array of Classes. 1314 * 1315 * <p> 1316 * This method calls {@link #isAssignable(Class, Class) isAssignable} for each Class pair in the input arrays. It can be 1317 * used to check if a set of arguments (the first parameter) are suitably compatible with a set of method parameter 1318 * types (the second parameter). 1319 * </p> 1320 * 1321 * <p> 1322 * Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, this method takes into account widenings of 1323 * primitive classes and {@code null}s. 1324 * </p> 1325 * 1326 * <p> 1327 * Primitive widenings allow an int to be assigned to a {@code long}, {@code float} or {@code double}. This method 1328 * returns the correct result for these cases. 1329 * </p> 1330 * 1331 * <p> 1332 * {@code null} may be assigned to any reference type. This method will return {@code true} if {@code null} is passed in 1333 * and the toClass is non-primitive. 1334 * </p> 1335 * 1336 * <p> 1337 * Specifically, this method tests whether the type represented by the specified {@link Class} parameter can be 1338 * converted to the type represented by this {@link Class} object via an identity conversion widening primitive or 1339 * widening reference conversion. See <em><a href="https://docs.oracle.com/javase/specs/">The Java Language 1340 * Specification</a></em>, sections 5.1.1, 5.1.2 and 5.1.4 for details. 1341 * </p> 1342 * 1343 * <p> 1344 * <strong>Since Lang 3.0,</strong> this method will default behavior for calculating assignability between primitive 1345 * and wrapper types <em>corresponding to the running Java version</em>; i.e. autoboxing will be the default behavior in 1346 * VMs running Java versions > 1.5. 1347 * </p> 1348 * 1349 * @param classArray the array of Classes to check, may be {@code null} 1350 * @param toClassArray the array of Classes to try to assign into, may be {@code null} 1351 * @return {@code true} if assignment possible 1352 */ 1353 public static boolean isAssignable(final Class<?>[] classArray, final Class<?>... toClassArray) { 1354 return isAssignable(classArray, toClassArray, true); 1355 } 1356 1357 /** 1358 * Checks if an array of Classes can be assigned to another array of Classes. 1359 * 1360 * <p> 1361 * This method calls {@link #isAssignable(Class, Class) isAssignable} for each Class pair in the input arrays. It can be 1362 * used to check if a set of arguments (the first parameter) are suitably compatible with a set of method parameter 1363 * types (the second parameter). 1364 * </p> 1365 * 1366 * <p> 1367 * Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, this method takes into account widenings of 1368 * primitive classes and {@code null}s. 1369 * </p> 1370 * 1371 * <p> 1372 * Primitive widenings allow an int to be assigned to a {@code long}, {@code float} or {@code double}. This method 1373 * returns the correct result for these cases. 1374 * </p> 1375 * 1376 * <p> 1377 * {@code null} may be assigned to any reference type. This method will return {@code true} if {@code null} is passed in 1378 * and the toClass is non-primitive. 1379 * </p> 1380 * 1381 * <p> 1382 * Specifically, this method tests whether the type represented by the specified {@link Class} parameter can be 1383 * converted to the type represented by this {@link Class} object via an identity conversion widening primitive or 1384 * widening reference conversion. See <em><a href="https://docs.oracle.com/javase/specs/">The Java Language 1385 * Specification</a></em>, sections 5.1.1, 5.1.2 and 5.1.4 for details. 1386 * </p> 1387 * 1388 * @param classArray the array of Classes to check, may be {@code null} 1389 * @param toClassArray the array of Classes to try to assign into, may be {@code null} 1390 * @param autoboxing whether to use implicit autoboxing/unboxing between primitives and wrappers 1391 * @return {@code true} if assignment possible 1392 */ 1393 public static boolean isAssignable(Class<?>[] classArray, Class<?>[] toClassArray, final boolean autoboxing) { 1394 if (!ArrayUtils.isSameLength(classArray, toClassArray)) { 1395 return false; 1396 } 1397 classArray = ArrayUtils.nullToEmpty(classArray); 1398 toClassArray = ArrayUtils.nullToEmpty(toClassArray); 1399 for (int i = 0; i < classArray.length; i++) { 1400 if (!isAssignable(classArray[i], toClassArray[i], autoboxing)) { 1401 return false; 1402 } 1403 } 1404 return true; 1405 } 1406 1407 /** 1408 * Is the specified class an inner class or static nested class. 1409 * 1410 * @param cls the class to check, may be null 1411 * @return {@code true} if the class is an inner or static nested class, false if not or {@code null} 1412 */ 1413 public static boolean isInnerClass(final Class<?> cls) { 1414 return cls != null && cls.getEnclosingClass() != null; 1415 } 1416 1417 /** 1418 * Returns whether the given {@code type} is a primitive or primitive wrapper ({@link Boolean}, {@link Byte}, 1419 * {@link Character}, {@link Short}, {@link Integer}, {@link Long}, {@link Double}, {@link Float}). 1420 * 1421 * @param type The class to query or null. 1422 * @return true if the given {@code type} is a primitive or primitive wrapper ({@link Boolean}, {@link Byte}, 1423 * {@link Character}, {@link Short}, {@link Integer}, {@link Long}, {@link Double}, {@link Float}). 1424 * @since 3.1 1425 */ 1426 public static boolean isPrimitiveOrWrapper(final Class<?> type) { 1427 if (type == null) { 1428 return false; 1429 } 1430 return type.isPrimitive() || isPrimitiveWrapper(type); 1431 } 1432 /** 1433 * Returns whether the given {@code type} is a primitive wrapper ({@link Boolean}, {@link Byte}, {@link Character}, 1434 * {@link Short}, {@link Integer}, {@link Long}, {@link Double}, {@link Float}). 1435 * 1436 * @param type The class to query or null. 1437 * @return true if 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 * @since 3.1 1440 */ 1441 public static boolean isPrimitiveWrapper(final Class<?> type) { 1442 return wrapperPrimitiveMap.containsKey(type); 1443 } 1444 1445 /** 1446 * Tests whether a {@link Class} is public. 1447 * @param cls Class to test. 1448 * @return {@code true} if {@code cls} is public. 1449 * @since 3.13.0 1450 */ 1451 public static boolean isPublic(final Class<?> cls) { 1452 return Modifier.isPublic(cls.getModifiers()); 1453 } 1454 1455 /** 1456 * Converts the specified array of primitive Class objects to an array of its corresponding wrapper Class objects. 1457 * 1458 * @param classes the class array to convert, may be null or empty 1459 * @return an array which contains for each given class, the wrapper class or the original class if class is not a 1460 * primitive. {@code null} if null input. Empty array if an empty array passed in. 1461 * @since 2.1 1462 */ 1463 public static Class<?>[] primitivesToWrappers(final Class<?>... classes) { 1464 if (classes == null) { 1465 return null; 1466 } 1467 1468 if (classes.length == 0) { 1469 return classes; 1470 } 1471 1472 final Class<?>[] convertedClasses = new Class[classes.length]; 1473 Arrays.setAll(convertedClasses, i -> primitiveToWrapper(classes[i])); 1474 return convertedClasses; 1475 } 1476 1477 /** 1478 * Converts the specified primitive Class object to its corresponding wrapper Class object. 1479 * 1480 * <p> 1481 * NOTE: From v2.2, this method handles {@code Void.TYPE}, returning {@code Void.TYPE}. 1482 * </p> 1483 * 1484 * @param cls the class to convert, may be null 1485 * @return the wrapper class for {@code cls} or {@code cls} if {@code cls} is not a primitive. {@code null} if null 1486 * input. 1487 * @since 2.1 1488 */ 1489 public static Class<?> primitiveToWrapper(final Class<?> cls) { 1490 Class<?> convertedClass = cls; 1491 if (cls != null && cls.isPrimitive()) { 1492 convertedClass = primitiveWrapperMap.get(cls); 1493 } 1494 return convertedClass; 1495 } 1496 1497 /** 1498 * Converts a class name to a JLS style class name. 1499 * 1500 * @param className the class name 1501 * @return the converted name 1502 * @throws NullPointerException if the className is null 1503 */ 1504 private static String toCanonicalName(final String className) { 1505 String canonicalName = StringUtils.deleteWhitespace(className); 1506 Objects.requireNonNull(canonicalName, "className"); 1507 if (canonicalName.endsWith("[]")) { 1508 final StringBuilder classNameBuffer = new StringBuilder(); 1509 while (canonicalName.endsWith("[]")) { 1510 canonicalName = canonicalName.substring(0, canonicalName.length() - 2); 1511 classNameBuffer.append("["); 1512 } 1513 final String abbreviation = abbreviationMap.get(canonicalName); 1514 if (abbreviation != null) { 1515 classNameBuffer.append(abbreviation); 1516 } else { 1517 classNameBuffer.append("L").append(canonicalName).append(";"); 1518 } 1519 canonicalName = classNameBuffer.toString(); 1520 } 1521 return canonicalName; 1522 } 1523 1524 /** 1525 * Converts an array of {@link Object} in to an array of {@link Class} objects. If any of these objects is null, a null 1526 * element will be inserted into the array. 1527 * 1528 * <p> 1529 * This method returns {@code null} for a {@code null} input array. 1530 * </p> 1531 * 1532 * @param array an {@link Object} array 1533 * @return a {@link Class} array, {@code null} if null array input 1534 * @since 2.4 1535 */ 1536 public static Class<?>[] toClass(final Object... array) { 1537 if (array == null) { 1538 return null; 1539 } 1540 if (array.length == 0) { 1541 return ArrayUtils.EMPTY_CLASS_ARRAY; 1542 } 1543 final Class<?>[] classes = new Class[array.length]; 1544 Arrays.setAll(classes, i -> array[i] == null ? null : array[i].getClass()); 1545 return classes; 1546 } 1547 1548 /** 1549 * Decides if the part that was just copied to its destination location in the work array can be kept as it was copied 1550 * 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 1551 * case the {@code source} index, from where the characters are copied points one position after the last character, 1552 * a.k.a. {@code source == 1553 * originalLength} 1554 * 1555 * <p> 1556 * 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 1557 * character that are to be copied is less than or equal to the desired length. 1558 * </p> 1559 * 1560 * @param runAheadTarget the target index (where the characters were copied to) pointing after the last character copied 1561 * when the current part was copied 1562 * @param source the source index (where the characters were copied from) pointing after the last character copied when 1563 * the current part was copied 1564 * @param originalLength the original length of the class full name, which is abbreviated 1565 * @param desiredLength the desired length of the abbreviated class name 1566 * @return {@code true} if it can be kept in its original length {@code false} if the current part has to be abbreviated 1567 * and 1568 */ 1569 private static boolean useFull(final int runAheadTarget, final int source, final int originalLength, final int desiredLength) { 1570 return source >= originalLength || runAheadTarget + originalLength - source <= desiredLength; 1571 } 1572 1573 /** 1574 * Converts the specified array of wrapper Class objects to an array of its corresponding primitive Class objects. 1575 * 1576 * <p> 1577 * This method invokes {@code wrapperToPrimitive()} for each element of the passed in array. 1578 * </p> 1579 * 1580 * @param classes the class array to convert, may be null or empty 1581 * @return an array which contains for each given class, the primitive class or <b>null</b> if the original class is not 1582 * a wrapper class. {@code null} if null input. Empty array if an empty array passed in. 1583 * @see #wrapperToPrimitive(Class) 1584 * @since 2.4 1585 */ 1586 public static Class<?>[] wrappersToPrimitives(final Class<?>... classes) { 1587 if (classes == null) { 1588 return null; 1589 } 1590 1591 if (classes.length == 0) { 1592 return classes; 1593 } 1594 1595 final Class<?>[] convertedClasses = new Class[classes.length]; 1596 Arrays.setAll(convertedClasses, i -> wrapperToPrimitive(classes[i])); 1597 return convertedClasses; 1598 } 1599 1600 /** 1601 * Converts the specified wrapper class to its corresponding primitive class. 1602 * 1603 * <p> 1604 * This method is the counter part of {@code primitiveToWrapper()}. If the passed in class is a wrapper class for a 1605 * primitive type, this primitive type will be returned (e.g. {@code Integer.TYPE} for {@code Integer.class}). For other 1606 * classes, or if the parameter is <b>null</b>, the return value is <b>null</b>. 1607 * </p> 1608 * 1609 * @param cls the class to convert, may be <b>null</b> 1610 * @return the corresponding primitive type if {@code cls} is a wrapper class, <b>null</b> otherwise 1611 * @see #primitiveToWrapper(Class) 1612 * @since 2.4 1613 */ 1614 public static Class<?> wrapperToPrimitive(final Class<?> cls) { 1615 return wrapperPrimitiveMap.get(cls); 1616 } 1617 1618 /** 1619 * ClassUtils instances should NOT be constructed in standard programming. Instead, the class should be used as 1620 * {@code ClassUtils.getShortClassName(cls)}. 1621 * 1622 * <p> 1623 * This constructor is public to permit tools that require a JavaBean instance to operate. 1624 * </p> 1625 * 1626 * @deprecated TODO Make private in 4.0. 1627 */ 1628 @Deprecated 1629 public ClassUtils() { 1630 // empty 1631 } 1632 1633}