1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * https://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.lang3;
18
19 import java.lang.reflect.Method;
20 import java.lang.reflect.Modifier;
21 import java.util.ArrayDeque;
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.Comparator;
25 import java.util.Deque;
26 import java.util.HashMap;
27 import java.util.HashSet;
28 import java.util.Iterator;
29 import java.util.LinkedHashSet;
30 import java.util.List;
31 import java.util.Map;
32 import java.util.Objects;
33 import java.util.Set;
34 import java.util.concurrent.atomic.AtomicReference;
35 import java.util.stream.Collectors;
36
37 /**
38 * Operates on classes without using reflection.
39 *
40 * <p>
41 * This class handles invalid {@code null} inputs as best it can. Each method documents its behavior in more detail.
42 * </p>
43 *
44 * <p>
45 * The notion of a {@code canonical name} includes the human-readable name for the type, for example {@code int[]}. The
46 * non-canonical method variants work with the JVM names, such as {@code [I}.
47 * </p>
48 *
49 * @since 2.0
50 */
51 public class ClassUtils {
52
53 /**
54 * Inclusivity literals for {@link #hierarchy(Class, Interfaces)}.
55 *
56 * @since 3.2
57 */
58 public enum Interfaces {
59
60 /** Includes interfaces. */
61 INCLUDE,
62
63 /** Excludes interfaces. */
64 EXCLUDE
65 }
66
67 /**
68 * The JLS-specified maximum class name length {@value}.
69 *
70 * @see Class#forName(String, boolean, ClassLoader)
71 * @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>
72 * @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>
73 * @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>
74 */
75 private static final int MAX_CLASS_NAME_LENGTH = 65535;
76
77 /**
78 * The JVM-specified {@code CONSTANT_Class_info} structure defines an array type descriptor is valid only if it represents {@value} or fewer dimensions.
79 *
80 * @see Class#forName(String, boolean, ClassLoader)
81 * @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>
82 * @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>
83 * @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>
84 */
85 private static final int MAX_JVM_ARRAY_DIMENSION = 255;
86
87 /**
88 * The maximum number of array dimensions.
89 */
90 private static final int MAX_DIMENSIONS = 255;
91
92 private static final Comparator<Class<?>> COMPARATOR = (o1, o2) -> Objects.compare(getName(o1), getName(o2), String::compareTo);
93
94 /**
95 * The package separator character: {@code '.' == {@value}}.
96 */
97 public static final char PACKAGE_SEPARATOR_CHAR = '.';
98
99 /**
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 }