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