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