/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.commons.lang3;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang3.mutable.MutableObject;
Operates on classes without using reflection.
This class handles invalid null
inputs as best it can. Each method documents its behavior in more detail.
The notion of a canonical name
includes the human readable name for the type, for example int[]
. The non-canonical method variants work with the JVM names, such as [I
.
Since: 2.0
/**
* <p>Operates on classes without using reflection.</p>
*
* <p>This class handles invalid {@code null} inputs as best it can.
* Each method documents its behavior in more detail.</p>
*
* <p>The notion of a {@code canonical name} includes the human
* readable name for the type, for example {@code int[]}. The
* non-canonical method variants work with the JVM names, such as
* {@code [I}. </p>
*
* @since 2.0
*/
public class ClassUtils {
Inclusivity literals for ClassUtils.hierarchy(Class<?>, Interfaces)
. Since: 3.2
/**
* Inclusivity literals for {@link #hierarchy(Class, Interfaces)}.
* @since 3.2
*/
public enum Interfaces {
Includes interfaces. /** Includes interfaces. */
INCLUDE,
Excludes interfaces. /** Excludes interfaces. */
EXCLUDE
}
The package separator character: '.' == {@value}
. /**
* The package separator character: {@code '.' == {@value}}.
*/
public static final char PACKAGE_SEPARATOR_CHAR = '.';
The package separator String: "."
. /**
* The package separator String: {@code "."}.
*/
public static final String PACKAGE_SEPARATOR = String.valueOf(PACKAGE_SEPARATOR_CHAR);
The inner class separator character: '$' == {@value}
. /**
* The inner class separator character: {@code '$' == {@value}}.
*/
public static final char INNER_CLASS_SEPARATOR_CHAR = '$';
The inner class separator String: "$"
. /**
* The inner class separator String: {@code "$"}.
*/
public static final String INNER_CLASS_SEPARATOR = String.valueOf(INNER_CLASS_SEPARATOR_CHAR);
Maps names of primitives to their corresponding primitive Class
es. /**
* Maps names of primitives to their corresponding primitive {@code Class}es.
*/
private static final Map<String, Class<?>> namePrimitiveMap = new HashMap<>();
static {
namePrimitiveMap.put("boolean", Boolean.TYPE);
namePrimitiveMap.put("byte", Byte.TYPE);
namePrimitiveMap.put("char", Character.TYPE);
namePrimitiveMap.put("short", Short.TYPE);
namePrimitiveMap.put("int", Integer.TYPE);
namePrimitiveMap.put("long", Long.TYPE);
namePrimitiveMap.put("double", Double.TYPE);
namePrimitiveMap.put("float", Float.TYPE);
namePrimitiveMap.put("void", Void.TYPE);
}
Maps primitive Class
es to their corresponding wrapper Class
. /**
* Maps primitive {@code Class}es to their corresponding wrapper {@code Class}.
*/
private static final Map<Class<?>, Class<?>> primitiveWrapperMap = new HashMap<>();
static {
primitiveWrapperMap.put(Boolean.TYPE, Boolean.class);
primitiveWrapperMap.put(Byte.TYPE, Byte.class);
primitiveWrapperMap.put(Character.TYPE, Character.class);
primitiveWrapperMap.put(Short.TYPE, Short.class);
primitiveWrapperMap.put(Integer.TYPE, Integer.class);
primitiveWrapperMap.put(Long.TYPE, Long.class);
primitiveWrapperMap.put(Double.TYPE, Double.class);
primitiveWrapperMap.put(Float.TYPE, Float.class);
primitiveWrapperMap.put(Void.TYPE, Void.TYPE);
}
Maps wrapper Class
es to their corresponding primitive types. /**
* Maps wrapper {@code Class}es to their corresponding primitive types.
*/
private static final Map<Class<?>, Class<?>> wrapperPrimitiveMap = new HashMap<>();
static {
for (final Map.Entry<Class<?>, Class<?>> entry : primitiveWrapperMap.entrySet()) {
final Class<?> primitiveClass = entry.getKey();
final Class<?> wrapperClass = entry.getValue();
if (!primitiveClass.equals(wrapperClass)) {
wrapperPrimitiveMap.put(wrapperClass, primitiveClass);
}
}
}
Maps a primitive class name to its corresponding abbreviation used in array class names.
/**
* Maps a primitive class name to its corresponding abbreviation used in array class names.
*/
private static final Map<String, String> abbreviationMap;
Maps an abbreviation used in array class names to corresponding primitive class name.
/**
* Maps an abbreviation used in array class names to corresponding primitive class name.
*/
private static final Map<String, String> reverseAbbreviationMap;
// Feed abbreviation maps
static {
final Map<String, String> m = new HashMap<>();
m.put("int", "I");
m.put("boolean", "Z");
m.put("float", "F");
m.put("long", "J");
m.put("short", "S");
m.put("byte", "B");
m.put("double", "D");
m.put("char", "C");
final Map<String, String> r = new HashMap<>();
for (final Map.Entry<String, String> e : m.entrySet()) {
r.put(e.getValue(), e.getKey());
}
abbreviationMap = Collections.unmodifiableMap(m);
reverseAbbreviationMap = Collections.unmodifiableMap(r);
}
ClassUtils instances should NOT be constructed in standard programming. Instead, the class should be used as ClassUtils.getShortClassName(cls)
.
This constructor is public to permit tools that require a JavaBean
instance to operate.
/**
* <p>ClassUtils instances should NOT be constructed in standard programming.
* Instead, the class should be used as
* {@code ClassUtils.getShortClassName(cls)}.</p>
*
* <p>This constructor is public to permit tools that require a JavaBean
* instance to operate.</p>
*/
public ClassUtils() {
super();
}
// Short class name
// ----------------------------------------------------------------------
Gets the class name of the object
without the package name or names.
The method looks up the class of the object and then converts the name of the class invoking getShortClassName(Class<?>)
(see relevant notes there).
Params: - object – the class to get the short name for, may be
null
- valueIfNull – the value to return if the object is
null
Returns: the class name of the object without the package name, or valueIfNull
if the argument object
is null
/**
* <p>Gets the class name of the {@code object} without the package name or names.</p>
*
* <p>The method looks up the class of the object and then converts the name of the class invoking
* {@link #getShortClassName(Class)} (see relevant notes there).</p>
*
* @param object the class to get the short name for, may be {@code null}
* @param valueIfNull the value to return if the object is {@code null}
* @return the class name of the object without the package name, or {@code valueIfNull}
* if the argument {@code object} is {@code null}
*/
public static String getShortClassName(final Object object, final String valueIfNull) {
if (object == null) {
return valueIfNull;
}
return getShortClassName(object.getClass());
}
Gets the class name minus the package name from a Class
.
This method simply gets the name using Class.getName()
and then calls getShortClassName(Class<?>)
. See relevant notes there.
Params: - cls – the class to get the short name for.
Returns: the class name without the package name or an empty string. If the class is an inner class then the returned value will contain the outer class or classes separated with .
(dot) character.
/**
* <p>Gets the class name minus the package name from a {@code Class}.</p>
*
* <p>This method simply gets the name using {@code Class.getName()} and then calls
* {@link #getShortClassName(Class)}. See relevant notes there.</p>
*
* @param cls the class to get the short name for.
* @return the class name without the package name or an empty string. If the class
* is an inner class then the returned value will contain the outer class
* or classes separated with {@code .} (dot) character.
*/
public static String getShortClassName(final Class<?> cls) {
if (cls == null) {
return StringUtils.EMPTY;
}
return getShortClassName(cls.getName());
}
Gets the class name minus the package name from a String.
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 JDK method Class.getName()
returns it, and not the usual way as we write it, for example in import statements, or as it is formatted by Class.getCanonicalName()
.
The difference is is significant only in case of classes that are inner classes of some other classes. In this case the separator between the outer and inner class (possibly on multiple hierarchy level) has to be $
(dollar sign) and not .
(dot), as it is returned by Class.getName()
Note that this method is called from the getShortClassName(Class<?>)
method using the string returned by Class.getName()
.
Note that this method differs from getSimpleName(Class<?>)
in that this will return, for example "Map.Entry"
whilst the java.lang.Class
variant will simply return "Entry"
. In this example the argument className
is the string java.util.Map$Entry
(note the $
sign.
Params: - className – the className to get the short name for. It has to be formatted as returned by
Class.getName()
and not Class.getCanonicalName()
Returns: the class name of the class without the package name or an empty string. If the class is an inner class then value contains the outer class or classes and the separator is replaced to be .
(dot) character.
/**
* <p>Gets the class name minus the package name from a String.</p>
*
* <p>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 JDK method {@code Class.getName()} returns it, and not the usual way as we write it, for example in import
* statements, or as it is formatted by {@code Class.getCanonicalName()}.</p>
*
* <p>The difference is is significant only in case of classes that are inner classes of some other
* classes. In this case the separator between the outer and inner class (possibly on multiple hierarchy level) has
* to be {@code $} (dollar sign) and not {@code .} (dot), as it is returned by {@code Class.getName()}</p>
*
* <p>Note that this method is called from the {@link #getShortClassName(Class)} method using the string
* returned by {@code Class.getName()}.</p>
*
* <p>Note that this method differs from {@link #getSimpleName(Class)} in that this will
* return, for example {@code "Map.Entry"} whilst the {@code java.lang.Class} variant will simply
* return {@code "Entry"}. In this example the argument {@code className} is the string
* {@code java.util.Map$Entry} (note the {@code $} sign.</p>
*
* @param className the className to get the short name for. It has to be formatted as returned by
* {@code Class.getName()} and not {@code Class.getCanonicalName()}
* @return the class name of the class without the package name or an empty string. If the class is
* an inner class then value contains the outer class or classes and the separator is replaced
* to be {@code .} (dot) character.
*/
public static String getShortClassName(String className) {
if (StringUtils.isEmpty(className)) {
return StringUtils.EMPTY;
}
final StringBuilder arrayPrefix = new StringBuilder();
// Handle array encoding
if (className.startsWith("[")) {
while (className.charAt(0) == '[') {
className = className.substring(1);
arrayPrefix.append("[]");
}
// Strip Object type encoding
if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';') {
className = className.substring(1, className.length() - 1);
}
if (reverseAbbreviationMap.containsKey(className)) {
className = reverseAbbreviationMap.get(className);
}
}
final int lastDotIdx = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR);
final int innerIdx = className.indexOf(
INNER_CLASS_SEPARATOR_CHAR, lastDotIdx == -1 ? 0 : lastDotIdx + 1);
String out = className.substring(lastDotIdx + 1);
if (innerIdx != -1) {
out = out.replace(INNER_CLASS_SEPARATOR_CHAR, PACKAGE_SEPARATOR_CHAR);
}
return out + arrayPrefix;
}
Null-safe version of cls.getSimpleName()
Params: - cls – the class for which to get the simple name; may be null
See Also: Returns: the simple class name or the empty string in case the argument is null
Since: 3.0
/**
* <p>Null-safe version of {@code cls.getSimpleName()}</p>
*
* @param cls the class for which to get the simple name; may be null
* @return the simple class name or the empty string in case the argument is {@code null}
* @since 3.0
* @see Class#getSimpleName()
*/
public static String getSimpleName(final Class<?> cls) {
return getSimpleName(cls, StringUtils.EMPTY);
}
Null-safe version of cls.getSimpleName()
Params: - cls – the class for which to get the simple name; may be null
- valueIfNull – the value to return if null
See Also: Returns: the simple class name or valueIfNull
if the argument cls
is null
Since: 3.0
/**
* <p>Null-safe version of {@code cls.getSimpleName()}</p>
*
* @param cls the class for which to get the simple name; may be null
* @param valueIfNull the value to return if null
* @return the simple class name or {@code valueIfNull} if the
* argument {@code cls} is {@code null}
* @since 3.0
* @see Class#getSimpleName()
*/
public static String getSimpleName(final Class<?> cls, final String valueIfNull) {
return cls == null ? valueIfNull : cls.getSimpleName();
}
Null-safe version of object.getClass().getSimpleName()
It is to note that this method is overloaded and in case the argument object
is a Class
object then the getSimpleName(Class<?>)
will be invoked. If this is a significant possibility then the caller should check this case and call
getSimpleName(Class.class)
or just simply use the string literal "Class"
, which is the result of the method in that case.
Params: - object – the object for which to get the simple class name; may be null
See Also: Returns: the simple class name or the empty string in case the argument is null
Since: 3.7
/**
* <p>Null-safe version of {@code object.getClass().getSimpleName()}</p>
*
* <p>It is to note that this method is overloaded and in case the argument {@code object} is a
* {@code Class} object then the {@link #getSimpleName(Class)} will be invoked. If this is
* a significant possibility then the caller should check this case and call {@code
* getSimpleName(Class.class)} or just simply use the string literal {@code "Class"}, which
* is the result of the method in that case.</p>
*
* @param object the object for which to get the simple class name; may be null
* @return the simple class name or the empty string in case the argument is {@code null}
* @since 3.7
* @see Class#getSimpleName()
*/
public static String getSimpleName(final Object object) {
return getSimpleName(object, StringUtils.EMPTY);
}
Null-safe version of object.getClass().getSimpleName()
Params: - object – the object for which to get the simple class name; may be null
- valueIfNull – the value to return if
object
is null
See Also: Returns: the simple class name or valueIfNull
if the argument object
is null
Since: 3.0
/**
* <p>Null-safe version of {@code object.getClass().getSimpleName()}</p>
*
* @param object the object for which to get the simple class name; may be null
* @param valueIfNull the value to return if {@code object} is {@code null}
* @return the simple class name or {@code valueIfNull} if the
* argument {@code object} is {@code null}
* @since 3.0
* @see Class#getSimpleName()
*/
public static String getSimpleName(final Object object, final String valueIfNull) {
return object == null ? valueIfNull : object.getClass().getSimpleName();
}
Null-safe version of cls.getName()
Params: - cls – the class for which to get the class name; may be null
See Also: Returns: the class name or the empty string in case the argument is null
Since: 3.7
/**
* <p>Null-safe version of {@code cls.getName()}</p>
*
* @param cls the class for which to get the class name; may be null
* @return the class name or the empty string in case the argument is {@code null}
* @since 3.7
* @see Class#getSimpleName()
*/
public static String getName(final Class<?> cls) {
return getName(cls, StringUtils.EMPTY);
}
Null-safe version of cls.getName()
Params: - cls – the class for which to get the class name; may be null
- valueIfNull – the return value if the argument
cls
is null
See Also: Returns: the class name or valueIfNull
Since: 3.7
/**
* <p>Null-safe version of {@code cls.getName()}</p>
*
* @param cls the class for which to get the class name; may be null
* @param valueIfNull the return value if the argument {@code cls} is {@code null}
* @return the class name or {@code valueIfNull}
* @since 3.7
* @see Class#getName()
*/
public static String getName(final Class<?> cls, final String valueIfNull) {
return cls == null ? valueIfNull : cls.getName();
}
Null-safe version of object.getClass().getName()
Params: - object – the object for which to get the class name; may be null
See Also: Returns: the class name or the empty String Since: 3.7
/**
* <p>Null-safe version of {@code object.getClass().getName()}</p>
*
* @param object the object for which to get the class name; may be null
* @return the class name or the empty String
* @since 3.7
* @see Class#getSimpleName()
*/
public static String getName(final Object object) {
return getName(object, StringUtils.EMPTY);
}
Null-safe version of object.getClass().getSimpleName()
Params: - object – the object for which to get the class name; may be null
- valueIfNull – the value to return if
object
is null
See Also: Returns: the class name or valueIfNull
Since: 3.0
/**
* <p>Null-safe version of {@code object.getClass().getSimpleName()}</p>
*
* @param object the object for which to get the class name; may be null
* @param valueIfNull the value to return if {@code object} is {@code null}
* @return the class name or {@code valueIfNull}
* @since 3.0
* @see Class#getName()
*/
public static String getName(final Object object, final String valueIfNull) {
return object == null ? valueIfNull : object.getClass().getName();
}
// Package name
// ----------------------------------------------------------------------
Gets the package name of an Object
.
Params: - object – the class to get the package name for, may be null
- valueIfNull – the value to return if null
Returns: the package name of the object, or the null value
/**
* <p>Gets the package name of an {@code Object}.</p>
*
* @param object the class to get the package name for, may be null
* @param valueIfNull the value to return if null
* @return the package name of the object, or the null value
*/
public static String getPackageName(final Object object, final String valueIfNull) {
if (object == null) {
return valueIfNull;
}
return getPackageName(object.getClass());
}
Gets the package name of a Class
.
Params: - cls – the class to get the package name for, may be
null
.
Returns: the package name or an empty string
/**
* <p>Gets the package name of a {@code Class}.</p>
*
* @param cls the class to get the package name for, may be {@code null}.
* @return the package name or an empty string
*/
public static String getPackageName(final Class<?> cls) {
if (cls == null) {
return StringUtils.EMPTY;
}
return getPackageName(cls.getName());
}
Gets the package name from a String
.
The string passed in is assumed to be a class name - it is not checked.
If the class is unpackaged, return an empty string.
Params: - className – the className to get the package name for, may be
null
Returns: the package name or an empty string
/**
* <p>Gets the package name from a {@code String}.</p>
*
* <p>The string passed in is assumed to be a class name - it is not checked.</p>
* <p>If the class is unpackaged, return an empty string.</p>
*
* @param className the className to get the package name for, may be {@code null}
* @return the package name or an empty string
*/
public static String getPackageName(String className) {
if (StringUtils.isEmpty(className)) {
return StringUtils.EMPTY;
}
// Strip array encoding
while (className.charAt(0) == '[') {
className = className.substring(1);
}
// Strip Object type encoding
if (className.charAt(0) == 'L' && className.charAt(className.length() - 1) == ';') {
className = className.substring(1);
}
final int i = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR);
if (i == -1) {
return StringUtils.EMPTY;
}
return className.substring(0, i);
}
// Abbreviated name
// ----------------------------------------------------------------------
Gets the abbreviated name of a Class
.
Params: - cls – the class to get the abbreviated name for, may be
null
- lengthHint – the desired length of the abbreviated name
Throws: - IllegalArgumentException – if len <= 0
See Also: Returns: the abbreviated name or an empty string Since: 3.4
/**
* <p>Gets the abbreviated name of a {@code Class}.</p>
*
* @param cls the class to get the abbreviated name for, may be {@code null}
* @param lengthHint the desired length of the abbreviated name
* @return the abbreviated name or an empty string
* @throws IllegalArgumentException if len <= 0
* @see #getAbbreviatedName(String, int)
* @since 3.4
*/
public static String getAbbreviatedName(final Class<?> cls, final int lengthHint) {
if (cls == null) {
return StringUtils.EMPTY;
}
return getAbbreviatedName(cls.getName(), lengthHint);
}
Gets the abbreviated class name from a String
.
The string passed in is assumed to be a class name - it is not checked.
The abbreviation algorithm will shorten the class name, usually without
significant loss of meaning.
The abbreviated class name will always include the complete package hierarchy.
If enough space is available, rightmost sub-packages will be displayed in full
length. The abbreviated package names will be shortened to a single character.
Only package names are shortened, the class simple name remains untouched. (See examples.)
The result will be longer than the desired length only if all the package names
shortened to a single character plus the class simple name with the separating dots
together are longer than the desired length. In other words, when the class name
cannot be shortened to the desired length.
If the class name can be shortened then the final length will be at most lengthHint
characters.
If the lengthHint
is zero or negative then the method throws exception. If you want to achieve the shortest possible version then use 1
as a lengthHint
.
Examples
className len return
null 1 ""
"java.lang.String" 5 "j.l.String"
"java.lang.String" 15 "j.lang.String"
"java.lang.String" 30 "java.lang.String"
"org.apache.commons.lang3.ClassUtils" 18 "o.a.c.l.ClassUtils"
Params: - className – the className to get the abbreviated name for, may be
null
- lengthHint – the desired length of the abbreviated name
Throws: - IllegalArgumentException – if
len <= 0
Returns: the abbreviated name or an empty string if the specified class name is null
or empty string. The abbreviated name may be longer than the desired length if it cannot be abbreviated to the desired length. Since: 3.4
/**
* <p>Gets the abbreviated class name from a {@code String}.</p>
*
* <p>The string passed in is assumed to be a class name - it is not checked.</p>
*
* <p>The abbreviation algorithm will shorten the class name, usually without
* significant loss of meaning.</p>
*
* <p>The abbreviated class name will always include the complete package hierarchy.
* If enough space is available, rightmost sub-packages will be displayed in full
* length. The abbreviated package names will be shortened to a single character.</p>
* <p>Only package names are shortened, the class simple name remains untouched. (See examples.)</p>
* <p>The result will be longer than the desired length only if all the package names
* shortened to a single character plus the class simple name with the separating dots
* together are longer than the desired length. In other words, when the class name
* cannot be shortened to the desired length.</p>
* <p>If the class name can be shortened then
* the final length will be at most {@code lengthHint} characters.</p>
* <p>If the {@code lengthHint} is zero or negative then the method
* throws exception. If you want to achieve the shortest possible version then
* use {@code 1} as a {@code lengthHint}.</p>
*
* <table>
* <caption>Examples</caption>
* <tr><td>className</td><td>len</td><td>return</td></tr>
* <tr><td> null</td><td> 1</td><td>""</td></tr>
* <tr><td>"java.lang.String"</td><td> 5</td><td>"j.l.String"</td></tr>
* <tr><td>"java.lang.String"</td><td>15</td><td>"j.lang.String"</td></tr>
* <tr><td>"java.lang.String"</td><td>30</td><td>"java.lang.String"</td></tr>
* <tr><td>"org.apache.commons.lang3.ClassUtils"</td><td>18</td><td>"o.a.c.l.ClassUtils"</td></tr>
* </table>
*
* @param className the className to get the abbreviated name for, may be {@code null}
* @param lengthHint the desired length of the abbreviated name
* @return the abbreviated name or an empty string if the specified
* class name is {@code null} or empty string. The abbreviated name may be
* longer than the desired length if it cannot be abbreviated to the desired length.
* @throws IllegalArgumentException if {@code len <= 0}
* @since 3.4
*/
public static String getAbbreviatedName(final String className, final int lengthHint) {
if (lengthHint <= 0) {
throw new IllegalArgumentException("len must be > 0");
}
if (className == null) {
return StringUtils.EMPTY;
}
if (className.length() <= lengthHint) {
return className;
}
final char[] abbreviated = className.toCharArray();
int target = 0;
int source = 0;
while (source < abbreviated.length) {
// copy the next part
int runAheadTarget = target;
while (source < abbreviated.length && abbreviated[source] != '.') {
abbreviated[runAheadTarget++] = abbreviated[source++];
}
++target;
if (useFull(runAheadTarget, source, abbreviated.length, lengthHint)
|| target > runAheadTarget) {
target = runAheadTarget;
}
// copy the '.' unless it was the last part
if (source < abbreviated.length) {
abbreviated[target++] = abbreviated[source++];
}
}
return new String(abbreviated, 0, target);
}
Decides if the part that was just copied to its destination location in the work array can be kept as it was copied 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 case the source
index, from where the characters are copied points one position after the last character, a.k.a. source ==
originalLength
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 character that are to be copied is less than or equal to the
desired length.
Params: - runAheadTarget – the target index (where the characters were
copied to) pointing after the last character
copied when the current part was copied
- source – the source index (where the characters were
copied from) pointing after the last
character copied when the current part was
copied
- originalLength – the original length of the class full name,
which is abbreviated
- desiredLength – the desired length of the abbreviated class
name
Returns: true
if it can be kept in its original length false
if the current part has to be abbreviated and
/**
* <p>Decides if the part that was just copied to its destination
* location in the work array can be kept as it was copied 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 case the {@code source}
* index, from where the characters are copied points one position
* after the last character, a.k.a. {@code source ==
* originalLength}</p>
*
* <p>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 character that are to be copied is less than or equal to the
* desired length.</p>
*
* @param runAheadTarget the target index (where the characters were
* copied to) pointing after the last character
* copied when the current part was copied
* @param source the source index (where the characters were
* copied from) pointing after the last
* character copied when the current part was
* copied
* @param originalLength the original length of the class full name,
* which is abbreviated
* @param desiredLength the desired length of the abbreviated class
* name
* @return {@code true} if it can be kept in its original length
* {@code false} if the current part has to be abbreviated and
*/
private static boolean useFull(final int runAheadTarget,
final int source,
final int originalLength,
final int desiredLength) {
return source >= originalLength ||
runAheadTarget + originalLength - source <= desiredLength;
}
// Superclasses/Superinterfaces
// ----------------------------------------------------------------------
Gets a List
of superclasses for the given class.
Params: - cls – the class to look up, may be
null
Returns: the List
of superclasses in order going up from this one null
if null input
/**
* <p>Gets a {@code List} of superclasses for the given class.</p>
*
* @param cls the class to look up, may be {@code null}
* @return the {@code List} of superclasses in order going up from this one
* {@code null} if null input
*/
public static List<Class<?>> getAllSuperclasses(final Class<?> cls) {
if (cls == null) {
return null;
}
final List<Class<?>> classes = new ArrayList<>();
Class<?> superclass = cls.getSuperclass();
while (superclass != null) {
classes.add(superclass);
superclass = superclass.getSuperclass();
}
return classes;
}
Gets a List
of all interfaces implemented by the given class and its superclasses.
The order is determined by looking through each interface in turn as
declared in the source file and following its hierarchy up. Then each
superclass is considered in the same way. Later duplicates are ignored,
so the order is maintained.
Params: - cls – the class to look up, may be
null
Returns: the List
of interfaces in order, null
if null input
/**
* <p>Gets a {@code List} of all interfaces implemented by the given
* class and its superclasses.</p>
*
* <p>The order is determined by looking through each interface in turn as
* declared in the source file and following its hierarchy up. Then each
* superclass is considered in the same way. Later duplicates are ignored,
* so the order is maintained.</p>
*
* @param cls the class to look up, may be {@code null}
* @return the {@code List} of interfaces in order,
* {@code null} if null input
*/
public static List<Class<?>> getAllInterfaces(final Class<?> cls) {
if (cls == null) {
return null;
}
final LinkedHashSet<Class<?>> interfacesFound = new LinkedHashSet<>();
getAllInterfaces(cls, interfacesFound);
return new ArrayList<>(interfacesFound);
}
Gets the interfaces for the specified class.
Params: - cls – the class to look up, may be
null
- interfacesFound – the
Set
of interfaces for the class
/**
* Gets the interfaces for the specified class.
*
* @param cls the class to look up, may be {@code null}
* @param interfacesFound the {@code Set} of interfaces for the class
*/
private static void getAllInterfaces(Class<?> cls, final HashSet<Class<?>> interfacesFound) {
while (cls != null) {
final Class<?>[] interfaces = cls.getInterfaces();
for (final Class<?> i : interfaces) {
if (interfacesFound.add(i)) {
getAllInterfaces(i, interfacesFound);
}
}
cls = cls.getSuperclass();
}
}
// Convert list
// ----------------------------------------------------------------------
Given a List
of class names, this method converts them into classes.
A new List
is returned. If the class name cannot be found, null
is stored in the List
. If the class name in the List
is null
, null
is stored in the output List
.
Params: - classNames – the classNames to change
Throws: - ClassCastException – if classNames contains a non String entry
Returns: a List
of Class objects corresponding to the class names, null
if null input
/**
* <p>Given a {@code List} of class names, this method converts them into classes.</p>
*
* <p>A new {@code List} is returned. If the class name cannot be found, {@code null}
* is stored in the {@code List}. If the class name in the {@code List} is
* {@code null}, {@code null} is stored in the output {@code List}.</p>
*
* @param classNames the classNames to change
* @return a {@code List} of Class objects corresponding to the class names,
* {@code null} if null input
* @throws ClassCastException if classNames contains a non String entry
*/
public static List<Class<?>> convertClassNamesToClasses(final List<String> classNames) {
if (classNames == null) {
return null;
}
final List<Class<?>> classes = new ArrayList<>(classNames.size());
for (final String className : classNames) {
try {
classes.add(Class.forName(className));
} catch (final Exception ex) {
classes.add(null);
}
}
return classes;
}
Given a List
of Class
objects, this method converts them into class names.
A new List
is returned. null
objects will be copied into the returned list as null
.
Params: - classes – the classes to change
Throws: - ClassCastException – if
classes
contains a non-Class
entry
Returns: a List
of class names corresponding to the Class objects, null
if null input
/**
* <p>Given a {@code List} of {@code Class} objects, this method converts
* them into class names.</p>
*
* <p>A new {@code List} is returned. {@code null} objects will be copied into
* the returned list as {@code null}.</p>
*
* @param classes the classes to change
* @return a {@code List} of class names corresponding to the Class objects,
* {@code null} if null input
* @throws ClassCastException if {@code classes} contains a non-{@code Class} entry
*/
public static List<String> convertClassesToClassNames(final List<Class<?>> classes) {
if (classes == null) {
return null;
}
final List<String> classNames = new ArrayList<>(classes.size());
for (final Class<?> cls : classes) {
if (cls == null) {
classNames.add(null);
} else {
classNames.add(cls.getName());
}
}
return classNames;
}
// Is assignable
// ----------------------------------------------------------------------
Checks if an array of Classes can be assigned to another array of Classes.
This method calls isAssignable
for each Class pair in the input arrays. It can be used to check if a set of arguments (the first parameter) are suitably compatible with a set of method parameter types (the second parameter).
Unlike the Class.isAssignableFrom(Class)
method, this method takes into account widenings of primitive classes and null
s.
Primitive widenings allow an int to be assigned to a long
, float
or double
. This method returns the correct result for these cases.
Null
may be assigned to any reference type. This method will return true
if null
is passed in and the toClass is non-primitive.
Specifically, this method tests whether the type represented by the specified Class
parameter can be converted to the type represented by this Class
object via an identity conversion widening primitive or widening reference conversion. See The Java Language Specification,
sections 5.1.1, 5.1.2 and 5.1.4 for details.
Since Lang 3.0, this method will default behavior for
calculating assignability between primitive and wrapper types corresponding
to the running Java version; i.e. autoboxing will be the default
behavior in VMs running Java versions > 1.5.
Params: - classArray – the array of Classes to check, may be
null
- toClassArray – the array of Classes to try to assign into, may be
null
Returns: true
if assignment possible
/**
* <p>Checks if an array of Classes can be assigned to another array of Classes.</p>
*
* <p>This method calls {@link #isAssignable(Class, Class) isAssignable} for each
* Class pair in the input arrays. It can be used to check if a set of arguments
* (the first parameter) are suitably compatible with a set of method parameter types
* (the second parameter).</p>
*
* <p>Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, this
* method takes into account widenings of primitive classes and
* {@code null}s.</p>
*
* <p>Primitive widenings allow an int to be assigned to a {@code long},
* {@code float} or {@code double}. This method returns the correct
* result for these cases.</p>
*
* <p>{@code Null} may be assigned to any reference type. This method will
* return {@code true} if {@code null} is passed in and the toClass is
* non-primitive.</p>
*
* <p>Specifically, this method tests whether the type represented by the
* specified {@code Class} parameter can be converted to the type
* represented by this {@code Class} object via an identity conversion
* widening primitive or widening reference conversion. See
* <em><a href="http://docs.oracle.com/javase/specs/">The Java Language Specification</a></em>,
* sections 5.1.1, 5.1.2 and 5.1.4 for details.</p>
*
* <p><strong>Since Lang 3.0,</strong> this method will default behavior for
* calculating assignability between primitive and wrapper types <em>corresponding
* to the running Java version</em>; i.e. autoboxing will be the default
* behavior in VMs running Java versions > 1.5.</p>
*
* @param classArray the array of Classes to check, may be {@code null}
* @param toClassArray the array of Classes to try to assign into, may be {@code null}
* @return {@code true} if assignment possible
*/
public static boolean isAssignable(final Class<?>[] classArray, final Class<?>... toClassArray) {
return isAssignable(classArray, toClassArray, true);
}
Checks if an array of Classes can be assigned to another array of Classes.
This method calls isAssignable
for each Class pair in the input arrays. It can be used to check if a set of arguments (the first parameter) are suitably compatible with a set of method parameter types (the second parameter).
Unlike the Class.isAssignableFrom(Class)
method, this method takes into account widenings of primitive classes and null
s.
Primitive widenings allow an int to be assigned to a long
, float
or double
. This method returns the correct result for these cases.
Null
may be assigned to any reference type. This method will return true
if null
is passed in and the toClass is non-primitive.
Specifically, this method tests whether the type represented by the specified Class
parameter can be converted to the type represented by this Class
object via an identity conversion widening primitive or widening reference conversion. See The Java Language Specification,
sections 5.1.1, 5.1.2 and 5.1.4 for details.
Params: - classArray – the array of Classes to check, may be
null
- toClassArray – the array of Classes to try to assign into, may be
null
- autoboxing – whether to use implicit autoboxing/unboxing between primitives and wrappers
Returns: true
if assignment possible
/**
* <p>Checks if an array of Classes can be assigned to another array of Classes.</p>
*
* <p>This method calls {@link #isAssignable(Class, Class) isAssignable} for each
* Class pair in the input arrays. It can be used to check if a set of arguments
* (the first parameter) are suitably compatible with a set of method parameter types
* (the second parameter).</p>
*
* <p>Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method, this
* method takes into account widenings of primitive classes and
* {@code null}s.</p>
*
* <p>Primitive widenings allow an int to be assigned to a {@code long},
* {@code float} or {@code double}. This method returns the correct
* result for these cases.</p>
*
* <p>{@code Null} may be assigned to any reference type. This method will
* return {@code true} if {@code null} is passed in and the toClass is
* non-primitive.</p>
*
* <p>Specifically, this method tests whether the type represented by the
* specified {@code Class} parameter can be converted to the type
* represented by this {@code Class} object via an identity conversion
* widening primitive or widening reference conversion. See
* <em><a href="http://docs.oracle.com/javase/specs/">The Java Language Specification</a></em>,
* sections 5.1.1, 5.1.2 and 5.1.4 for details.</p>
*
* @param classArray the array of Classes to check, may be {@code null}
* @param toClassArray the array of Classes to try to assign into, may be {@code null}
* @param autoboxing whether to use implicit autoboxing/unboxing between primitives and wrappers
* @return {@code true} if assignment possible
*/
public static boolean isAssignable(Class<?>[] classArray, Class<?>[] toClassArray, final boolean autoboxing) {
if (!ArrayUtils.isSameLength(classArray, toClassArray)) {
return false;
}
if (classArray == null) {
classArray = ArrayUtils.EMPTY_CLASS_ARRAY;
}
if (toClassArray == null) {
toClassArray = ArrayUtils.EMPTY_CLASS_ARRAY;
}
for (int i = 0; i < classArray.length; i++) {
if (!isAssignable(classArray[i], toClassArray[i], autoboxing)) {
return false;
}
}
return true;
}
Returns whether the given type
is a primitive or primitive wrapper (Boolean
, Byte
, Character
, Short
, Integer
, Long
, Double
, Float
). Params: - type –
The class to query or null.
Returns: true if the given type
is a primitive or primitive wrapper (Boolean
, Byte
, Character
, Short
, Integer
, Long
, Double
, Float
). Since: 3.1
/**
* Returns whether the given {@code type} is a primitive or primitive wrapper ({@link Boolean}, {@link Byte}, {@link Character},
* {@link Short}, {@link Integer}, {@link Long}, {@link Double}, {@link Float}).
*
* @param type
* The class to query or null.
* @return true if the given {@code type} is a primitive or primitive wrapper ({@link Boolean}, {@link Byte}, {@link Character},
* {@link Short}, {@link Integer}, {@link Long}, {@link Double}, {@link Float}).
* @since 3.1
*/
public static boolean isPrimitiveOrWrapper(final Class<?> type) {
if (type == null) {
return false;
}
return type.isPrimitive() || isPrimitiveWrapper(type);
}
Returns whether the given type
is a primitive wrapper (Boolean
, Byte
, Character
, Short
, Integer
, Long
, Double
, Float
). Params: - type –
The class to query or null.
Returns: true if the given type
is a primitive wrapper (Boolean
, Byte
, Character
, Short
, Integer
, Long
, Double
, Float
). Since: 3.1
/**
* Returns whether the given {@code type} is a primitive wrapper ({@link Boolean}, {@link Byte}, {@link Character}, {@link Short},
* {@link Integer}, {@link Long}, {@link Double}, {@link Float}).
*
* @param type
* The class to query or null.
* @return true if the given {@code type} is a primitive wrapper ({@link Boolean}, {@link Byte}, {@link Character}, {@link Short},
* {@link Integer}, {@link Long}, {@link Double}, {@link Float}).
* @since 3.1
*/
public static boolean isPrimitiveWrapper(final Class<?> type) {
return wrapperPrimitiveMap.containsKey(type);
}
Checks if one Class
can be assigned to a variable of another Class
.
Unlike the Class.isAssignableFrom(Class)
method, this method takes into account widenings of primitive classes and null
s.
Primitive widenings allow an int to be assigned to a long, float or
double. This method returns the correct result for these cases.
Null
may be assigned to any reference type. This method will return true
if null
is passed in and the toClass is non-primitive.
Specifically, this method tests whether the type represented by the specified Class
parameter can be converted to the type represented by this Class
object via an identity conversion widening primitive or widening reference conversion. See The Java Language Specification,
sections 5.1.1, 5.1.2 and 5.1.4 for details.
Since Lang 3.0, this method will default behavior for
calculating assignability between primitive and wrapper types corresponding
to the running Java version; i.e. autoboxing will be the default
behavior in VMs running Java versions > 1.5.
Params: - cls – the Class to check, may be null
- toClass – the Class to try to assign into, returns false if null
Returns: true
if assignment possible
/**
* <p>Checks if one {@code Class} can be assigned to a variable of
* another {@code Class}.</p>
*
* <p>Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method,
* this method takes into account widenings of primitive classes and
* {@code null}s.</p>
*
* <p>Primitive widenings allow an int to be assigned to a long, float or
* double. This method returns the correct result for these cases.</p>
*
* <p>{@code Null} may be assigned to any reference type. This method
* will return {@code true} if {@code null} is passed in and the
* toClass is non-primitive.</p>
*
* <p>Specifically, this method tests whether the type represented by the
* specified {@code Class} parameter can be converted to the type
* represented by this {@code Class} object via an identity conversion
* widening primitive or widening reference conversion. See
* <em><a href="http://docs.oracle.com/javase/specs/">The Java Language Specification</a></em>,
* sections 5.1.1, 5.1.2 and 5.1.4 for details.</p>
*
* <p><strong>Since Lang 3.0,</strong> this method will default behavior for
* calculating assignability between primitive and wrapper types <em>corresponding
* to the running Java version</em>; i.e. autoboxing will be the default
* behavior in VMs running Java versions > 1.5.</p>
*
* @param cls the Class to check, may be null
* @param toClass the Class to try to assign into, returns false if null
* @return {@code true} if assignment possible
*/
public static boolean isAssignable(final Class<?> cls, final Class<?> toClass) {
return isAssignable(cls, toClass, true);
}
Checks if one Class
can be assigned to a variable of another Class
.
Unlike the Class.isAssignableFrom(Class)
method, this method takes into account widenings of primitive classes and null
s.
Primitive widenings allow an int to be assigned to a long, float or
double. This method returns the correct result for these cases.
Null
may be assigned to any reference type. This method will return true
if null
is passed in and the toClass is non-primitive.
Specifically, this method tests whether the type represented by the specified Class
parameter can be converted to the type represented by this Class
object via an identity conversion widening primitive or widening reference conversion. See The Java Language Specification,
sections 5.1.1, 5.1.2 and 5.1.4 for details.
Params: - cls – the Class to check, may be null
- toClass – the Class to try to assign into, returns false if null
- autoboxing – whether to use implicit autoboxing/unboxing between primitives and wrappers
Returns: true
if assignment possible
/**
* <p>Checks if one {@code Class} can be assigned to a variable of
* another {@code Class}.</p>
*
* <p>Unlike the {@link Class#isAssignableFrom(java.lang.Class)} method,
* this method takes into account widenings of primitive classes and
* {@code null}s.</p>
*
* <p>Primitive widenings allow an int to be assigned to a long, float or
* double. This method returns the correct result for these cases.</p>
*
* <p>{@code Null} may be assigned to any reference type. This method
* will return {@code true} if {@code null} is passed in and the
* toClass is non-primitive.</p>
*
* <p>Specifically, this method tests whether the type represented by the
* specified {@code Class} parameter can be converted to the type
* represented by this {@code Class} object via an identity conversion
* widening primitive or widening reference conversion. See
* <em><a href="http://docs.oracle.com/javase/specs/">The Java Language Specification</a></em>,
* sections 5.1.1, 5.1.2 and 5.1.4 for details.</p>
*
* @param cls the Class to check, may be null
* @param toClass the Class to try to assign into, returns false if null
* @param autoboxing whether to use implicit autoboxing/unboxing between primitives and wrappers
* @return {@code true} if assignment possible
*/
public static boolean isAssignable(Class<?> cls, final Class<?> toClass, final boolean autoboxing) {
if (toClass == null) {
return false;
}
// have to check for null, as isAssignableFrom doesn't
if (cls == null) {
return !toClass.isPrimitive();
}
//autoboxing:
if (autoboxing) {
if (cls.isPrimitive() && !toClass.isPrimitive()) {
cls = primitiveToWrapper(cls);
if (cls == null) {
return false;
}
}
if (toClass.isPrimitive() && !cls.isPrimitive()) {
cls = wrapperToPrimitive(cls);
if (cls == null) {
return false;
}
}
}
if (cls.equals(toClass)) {
return true;
}
if (cls.isPrimitive()) {
if (!toClass.isPrimitive()) {
return false;
}
if (Integer.TYPE.equals(cls)) {
return Long.TYPE.equals(toClass)
|| Float.TYPE.equals(toClass)
|| Double.TYPE.equals(toClass);
}
if (Long.TYPE.equals(cls)) {
return Float.TYPE.equals(toClass)
|| Double.TYPE.equals(toClass);
}
if (Boolean.TYPE.equals(cls)) {
return false;
}
if (Double.TYPE.equals(cls)) {
return false;
}
if (Float.TYPE.equals(cls)) {
return Double.TYPE.equals(toClass);
}
if (Character.TYPE.equals(cls)) {
return Integer.TYPE.equals(toClass)
|| Long.TYPE.equals(toClass)
|| Float.TYPE.equals(toClass)
|| Double.TYPE.equals(toClass);
}
if (Short.TYPE.equals(cls)) {
return Integer.TYPE.equals(toClass)
|| Long.TYPE.equals(toClass)
|| Float.TYPE.equals(toClass)
|| Double.TYPE.equals(toClass);
}
if (Byte.TYPE.equals(cls)) {
return Short.TYPE.equals(toClass)
|| Integer.TYPE.equals(toClass)
|| Long.TYPE.equals(toClass)
|| Float.TYPE.equals(toClass)
|| Double.TYPE.equals(toClass);
}
// should never get here
return false;
}
return toClass.isAssignableFrom(cls);
}
Converts the specified primitive Class object to its corresponding
wrapper Class object.
NOTE: From v2.2, this method handles Void.TYPE
, returning Void.TYPE
.
Params: - cls – the class to convert, may be null
Returns: the wrapper class for cls
or cls
if cls
is not a primitive. null
if null input. Since: 2.1
/**
* <p>Converts the specified primitive Class object to its corresponding
* wrapper Class object.</p>
*
* <p>NOTE: From v2.2, this method handles {@code Void.TYPE},
* returning {@code Void.TYPE}.</p>
*
* @param cls the class to convert, may be null
* @return the wrapper class for {@code cls} or {@code cls} if
* {@code cls} is not a primitive. {@code null} if null input.
* @since 2.1
*/
public static Class<?> primitiveToWrapper(final Class<?> cls) {
Class<?> convertedClass = cls;
if (cls != null && cls.isPrimitive()) {
convertedClass = primitiveWrapperMap.get(cls);
}
return convertedClass;
}
Converts the specified array of primitive Class objects to an array of
its corresponding wrapper Class objects.
Params: - classes – the class array to convert, may be null or empty
Returns: an array which contains for each given class, the wrapper class or the original class if class is not a primitive. null
if null input. Empty array if an empty array passed in. Since: 2.1
/**
* <p>Converts the specified array of primitive Class objects to an array of
* its corresponding wrapper Class objects.</p>
*
* @param classes the class array to convert, may be null or empty
* @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.
* Empty array if an empty array passed in.
* @since 2.1
*/
public static Class<?>[] primitivesToWrappers(final Class<?>... classes) {
if (classes == null) {
return null;
}
if (classes.length == 0) {
return classes;
}
final Class<?>[] convertedClasses = new Class[classes.length];
for (int i = 0; i < classes.length; i++) {
convertedClasses[i] = primitiveToWrapper(classes[i]);
}
return convertedClasses;
}
Converts the specified wrapper class to its corresponding primitive
class.
This method is the counter part of primitiveToWrapper()
. If the passed in class is a wrapper class for a primitive type, this primitive type will be returned (e.g. Integer.TYPE
for Integer.class
). For other classes, or if the parameter is null, the return value is null.
Params: - cls – the class to convert, may be null
See Also: Returns: the corresponding primitive type if cls
is a wrapper class, null otherwise Since: 2.4
/**
* <p>Converts the specified wrapper class to its corresponding primitive
* class.</p>
*
* <p>This method is the counter part of {@code primitiveToWrapper()}.
* If the passed in class is a wrapper class for a primitive type, this
* primitive type will be returned (e.g. {@code Integer.TYPE} for
* {@code Integer.class}). For other classes, or if the parameter is
* <b>null</b>, the return value is <b>null</b>.</p>
*
* @param cls the class to convert, may be <b>null</b>
* @return the corresponding primitive type if {@code cls} is a
* wrapper class, <b>null</b> otherwise
* @see #primitiveToWrapper(Class)
* @since 2.4
*/
public static Class<?> wrapperToPrimitive(final Class<?> cls) {
return wrapperPrimitiveMap.get(cls);
}
Converts the specified array of wrapper Class objects to an array of
its corresponding primitive Class objects.
This method invokes wrapperToPrimitive()
for each element of the passed in array.
Params: - classes – the class array to convert, may be null or empty
See Also: Returns: an array which contains for each given class, the primitive class or
null if the original class is not a wrapper class. null
if null input. Empty array if an empty array passed in. Since: 2.4
/**
* <p>Converts the specified array of wrapper Class objects to an array of
* its corresponding primitive Class objects.</p>
*
* <p>This method invokes {@code wrapperToPrimitive()} for each element
* of the passed in array.</p>
*
* @param classes the class array to convert, may be null or empty
* @return an array which contains for each given class, the primitive class or
* <b>null</b> if the original class is not a wrapper class. {@code null} if null input.
* Empty array if an empty array passed in.
* @see #wrapperToPrimitive(Class)
* @since 2.4
*/
public static Class<?>[] wrappersToPrimitives(final Class<?>... classes) {
if (classes == null) {
return null;
}
if (classes.length == 0) {
return classes;
}
final Class<?>[] convertedClasses = new Class[classes.length];
for (int i = 0; i < classes.length; i++) {
convertedClasses[i] = wrapperToPrimitive(classes[i]);
}
return convertedClasses;
}
// Inner class
// ----------------------------------------------------------------------
Is the specified class an inner class or static nested class.
Params: - cls – the class to check, may be null
Returns: true
if the class is an inner or static nested class, false if not or null
/**
* <p>Is the specified class an inner class or static nested class.</p>
*
* @param cls the class to check, may be null
* @return {@code true} if the class is an inner or static nested class,
* false if not or {@code null}
*/
public static boolean isInnerClass(final Class<?> cls) {
return cls != null && cls.getEnclosingClass() != null;
}
// Class loading
// ----------------------------------------------------------------------
Returns the class represented by className
using the classLoader
. This implementation supports the syntaxes "java.util.Map.Entry[]
", "java.util.Map$Entry[]
", "[Ljava.util.Map.Entry;
", and "[Ljava.util.Map$Entry;
". Params: - classLoader – the class loader to use to load the class
- className – the class name
- initialize – whether the class must be initialized
Throws: - ClassNotFoundException – if the class is not found
Returns: the class represented by className
using the classLoader
/**
* Returns the class represented by {@code className} using the
* {@code classLoader}. This implementation supports the syntaxes
* "{@code java.util.Map.Entry[]}", "{@code java.util.Map$Entry[]}",
* "{@code [Ljava.util.Map.Entry;}", and "{@code [Ljava.util.Map$Entry;}".
*
* @param classLoader the class loader to use to load the class
* @param className the class name
* @param initialize whether the class must be initialized
* @return the class represented by {@code className} using the {@code classLoader}
* @throws ClassNotFoundException if the class is not found
*/
public static Class<?> getClass(
final ClassLoader classLoader, final String className, final boolean initialize) throws ClassNotFoundException {
try {
Class<?> clazz;
if (namePrimitiveMap.containsKey(className)) {
clazz = namePrimitiveMap.get(className);
} else {
clazz = Class.forName(toCanonicalName(className), initialize, classLoader);
}
return clazz;
} catch (final ClassNotFoundException ex) {
// allow path separators (.) as inner class name separators
final int lastDotIndex = className.lastIndexOf(PACKAGE_SEPARATOR_CHAR);
if (lastDotIndex != -1) {
try {
return getClass(classLoader, className.substring(0, lastDotIndex) +
INNER_CLASS_SEPARATOR_CHAR + className.substring(lastDotIndex + 1),
initialize);
} catch (final ClassNotFoundException ex2) { // NOPMD
// ignore exception
}
}
throw ex;
}
}
Returns the (initialized) class represented by className
using the classLoader
. This implementation supports the syntaxes "java.util.Map.Entry[]
", "java.util.Map$Entry[]
", "[Ljava.util.Map.Entry;
", and "[Ljava.util.Map$Entry;
". Params: - classLoader – the class loader to use to load the class
- className – the class name
Throws: - ClassNotFoundException – if the class is not found
Returns: the class represented by className
using the classLoader
/**
* Returns the (initialized) class represented by {@code className}
* using the {@code classLoader}. This implementation supports
* the syntaxes "{@code java.util.Map.Entry[]}",
* "{@code java.util.Map$Entry[]}", "{@code [Ljava.util.Map.Entry;}",
* and "{@code [Ljava.util.Map$Entry;}".
*
* @param classLoader the class loader to use to load the class
* @param className the class name
* @return the class represented by {@code className} using the {@code classLoader}
* @throws ClassNotFoundException if the class is not found
*/
public static Class<?> getClass(final ClassLoader classLoader, final String className) throws ClassNotFoundException {
return getClass(classLoader, className, true);
}
Returns the (initialized) class represented by className
using the current thread's context class loader. This implementation supports the syntaxes "java.util.Map.Entry[]
", "java.util.Map$Entry[]
", "[Ljava.util.Map.Entry;
", and "[Ljava.util.Map$Entry;
". Params: - className – the class name
Throws: - ClassNotFoundException – if the class is not found
Returns: the class represented by className
using the current thread's context class loader
/**
* Returns the (initialized) class represented by {@code className}
* using the current thread's context class loader. This implementation
* supports the syntaxes "{@code java.util.Map.Entry[]}",
* "{@code java.util.Map$Entry[]}", "{@code [Ljava.util.Map.Entry;}",
* and "{@code [Ljava.util.Map$Entry;}".
*
* @param className the class name
* @return the class represented by {@code className} using the current thread's context class loader
* @throws ClassNotFoundException if the class is not found
*/
public static Class<?> getClass(final String className) throws ClassNotFoundException {
return getClass(className, true);
}
Returns the class represented by className
using the current thread's context class loader. This implementation supports the syntaxes "java.util.Map.Entry[]
", "java.util.Map$Entry[]
", "[Ljava.util.Map.Entry;
", and "[Ljava.util.Map$Entry;
". Params: - className – the class name
- initialize – whether the class must be initialized
Throws: - ClassNotFoundException – if the class is not found
Returns: the class represented by className
using the current thread's context class loader
/**
* Returns the class represented by {@code className} using the
* current thread's context class loader. This implementation supports the
* syntaxes "{@code java.util.Map.Entry[]}", "{@code java.util.Map$Entry[]}",
* "{@code [Ljava.util.Map.Entry;}", and "{@code [Ljava.util.Map$Entry;}".
*
* @param className the class name
* @param initialize whether the class must be initialized
* @return the class represented by {@code className} using the current thread's context class loader
* @throws ClassNotFoundException if the class is not found
*/
public static Class<?> getClass(final String className, final boolean initialize) throws ClassNotFoundException {
final ClassLoader contextCL = Thread.currentThread().getContextClassLoader();
final ClassLoader loader = contextCL == null ? ClassUtils.class.getClassLoader() : contextCL;
return getClass(loader, className, initialize);
}
// Public method
// ----------------------------------------------------------------------
Returns the desired Method much like Class.getMethod
, however it ensures that the returned Method is from a public class or interface and not from an anonymous inner class. This means that the Method is invokable and doesn't fall foul of Java bug 4071957).
Set set = Collections.unmodifiableSet(...);
Method method = ClassUtils.getPublicMethod(set.getClass(), "isEmpty", new Class[0]);
Object result = method.invoke(set, new Object[]);
Params: - cls – the class to check, not null
- methodName – the name of the method
- parameterTypes – the list of parameters
Throws: - NullPointerException – if the class is null
- SecurityException – if a security violation occurred
- NoSuchMethodException – if the method is not found in the given class
or if the method doesn't conform with the requirements
Returns: the method
/**
* <p>Returns the desired Method much like {@code Class.getMethod}, however
* it ensures that the returned Method is from a public class or interface and not
* from an anonymous inner class. This means that the Method is invokable and
* doesn't fall foul of Java bug
* <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4071957">4071957</a>).</p>
*
* <pre>
* <code>Set set = Collections.unmodifiableSet(...);
* Method method = ClassUtils.getPublicMethod(set.getClass(), "isEmpty", new Class[0]);
* Object result = method.invoke(set, new Object[]);</code>
* </pre>
*
* @param cls the class to check, not null
* @param methodName the name of the method
* @param parameterTypes the list of parameters
* @return the method
* @throws NullPointerException if the class is null
* @throws SecurityException if a security violation occurred
* @throws NoSuchMethodException if the method is not found in the given class
* or if the method doesn't conform with the requirements
*/
public static Method getPublicMethod(final Class<?> cls, final String methodName, final Class<?>... parameterTypes)
throws NoSuchMethodException {
final Method declaredMethod = cls.getMethod(methodName, parameterTypes);
if (Modifier.isPublic(declaredMethod.getDeclaringClass().getModifiers())) {
return declaredMethod;
}
final List<Class<?>> candidateClasses = new ArrayList<>();
candidateClasses.addAll(getAllInterfaces(cls));
candidateClasses.addAll(getAllSuperclasses(cls));
for (final Class<?> candidateClass : candidateClasses) {
if (!Modifier.isPublic(candidateClass.getModifiers())) {
continue;
}
Method candidateMethod;
try {
candidateMethod = candidateClass.getMethod(methodName, parameterTypes);
} catch (final NoSuchMethodException ex) {
continue;
}
if (Modifier.isPublic(candidateMethod.getDeclaringClass().getModifiers())) {
return candidateMethod;
}
}
throw new NoSuchMethodException("Can't find a public method for " +
methodName + " " + ArrayUtils.toString(parameterTypes));
}
// ----------------------------------------------------------------------
Converts a class name to a JLS style class name.
Params: - className – the class name
Returns: the converted name
/**
* Converts a class name to a JLS style class name.
*
* @param className the class name
* @return the converted name
*/
private static String toCanonicalName(String className) {
className = StringUtils.deleteWhitespace(className);
Validate.notNull(className, "className must not be null.");
if (className.endsWith("[]")) {
final StringBuilder classNameBuffer = new StringBuilder();
while (className.endsWith("[]")) {
className = className.substring(0, className.length() - 2);
classNameBuffer.append("[");
}
final String abbreviation = abbreviationMap.get(className);
if (abbreviation != null) {
classNameBuffer.append(abbreviation);
} else {
classNameBuffer.append("L").append(className).append(";");
}
className = classNameBuffer.toString();
}
return className;
}
Converts an array of Object
in to an array of Class
objects. If any of these objects is null, a null element will be inserted into the array.
This method returns null
for a null
input array.
Params: - array – an
Object
array
Returns: a Class
array, null
if null array input Since: 2.4
/**
* <p>Converts an array of {@code Object} in to an array of {@code Class} objects.
* If any of these objects is null, a null element will be inserted into the array.</p>
*
* <p>This method returns {@code null} for a {@code null} input array.</p>
*
* @param array an {@code Object} array
* @return a {@code Class} array, {@code null} if null array input
* @since 2.4
*/
public static Class<?>[] toClass(final Object... array) {
if (array == null) {
return null;
} else if (array.length == 0) {
return ArrayUtils.EMPTY_CLASS_ARRAY;
}
final Class<?>[] classes = new Class[array.length];
for (int i = 0; i < array.length; i++) {
classes[i] = array[i] == null ? null : array[i].getClass();
}
return classes;
}
// Short canonical name
// ----------------------------------------------------------------------
Gets the canonical name minus the package name for an Object
.
Params: - object – the class to get the short name for, may be null
- valueIfNull – the value to return if null
Returns: the canonical name of the object without the package name, or the null value Since: 2.4
/**
* <p>Gets the canonical name minus the package name for an {@code Object}.</p>
*
* @param object the class to get the short name for, may be null
* @param valueIfNull the value to return if null
* @return the canonical name of the object without the package name, or the null value
* @since 2.4
*/
public static String getShortCanonicalName(final Object object, final String valueIfNull) {
if (object == null) {
return valueIfNull;
}
return getShortCanonicalName(object.getClass().getName());
}
Gets the canonical class name for a Class
.
Params: - cls – the class for which to get the canonical class name; may be null
See Also: Returns: the canonical name of the class, or the empty String Since: 3.7
/**
* <p>Gets the canonical class name for a {@code Class}.</p>
*
* @param cls the class for which to get the canonical class name; may be null
* @return the canonical name of the class, or the empty String
* @since 3.7
* @see Class#getCanonicalName()
*/
public static String getCanonicalName(final Class<?> cls) {
return getCanonicalName(cls, StringUtils.EMPTY);
}
Gets the canonical name for a Class
.
Params: - cls – the class for which to get the canonical class name; may be null
- valueIfNull – the return value if null
See Also: Returns: the canonical name of the class, or valueIfNull
Since: 3.7
/**
* <p>Gets the canonical name for a {@code Class}.</p>
*
* @param cls the class for which to get the canonical class name; may be null
* @param valueIfNull the return value if null
* @return the canonical name of the class, or {@code valueIfNull}
* @since 3.7
* @see Class#getCanonicalName()
*/
public static String getCanonicalName(final Class<?> cls, final String valueIfNull) {
if (cls == null) {
return valueIfNull;
}
final String canonicalName = cls.getCanonicalName();
return canonicalName == null ? valueIfNull : canonicalName;
}
Gets the canonical name for an Object
.
Params: - object – the object for which to get the canonical class name; may be null
See Also: Returns: the canonical name of the object, or the empty String Since: 3.7
/**
* <p>Gets the canonical name for an {@code Object}.</p>
*
* @param object the object for which to get the canonical class name; may be null
* @return the canonical name of the object, or the empty String
* @since 3.7
* @see Class#getCanonicalName()
*/
public static String getCanonicalName(final Object object) {
return getCanonicalName(object, StringUtils.EMPTY);
}
Gets the canonical name for an Object
.
Params: - object – the object for which to get the canonical class name; may be null
- valueIfNull – the return value if null
See Also: Returns: the canonical name of the object or valueIfNull
Since: 3.7
/**
* <p>Gets the canonical name for an {@code Object}.</p>
*
* @param object the object for which to get the canonical class name; may be null
* @param valueIfNull the return value if null
* @return the canonical name of the object or {@code valueIfNull}
* @since 3.7
* @see Class#getCanonicalName()
*/
public static String getCanonicalName(final Object object, final String valueIfNull) {
if (object == null) {
return valueIfNull;
}
final String canonicalName = object.getClass().getCanonicalName();
return canonicalName == null ? valueIfNull : canonicalName;
}
Gets the canonical name minus the package name from a Class
.
Params: - cls – the class for which to get the short canonical class name; may be null
Returns: the canonical name without the package name or an empty string Since: 2.4
/**
* <p>Gets the canonical name minus the package name from a {@code Class}.</p>
*
* @param cls the class for which to get the short canonical class name; may be null
* @return the canonical name without the package name or an empty string
* @since 2.4
*/
public static String getShortCanonicalName(final Class<?> cls) {
if (cls == null) {
return StringUtils.EMPTY;
}
return getShortCanonicalName(cls.getName());
}
Gets the canonical name minus the package name from a String.
The string passed in is assumed to be a class name - it is not checked.
Note that this method is mainly designed to handle the arrays and primitives properly. If the class is an inner class then the result value will not contain the outer classes. This way the behavior of this method is different from getShortClassName(String)
. The argument in that case is class name and not canonical name and the return value retains the outer classes.
Note that there is no way to reliably identify the part of the string representing the
package hierarchy and the part that is the outer class or classes in case of an inner class.
Trying to find the class would require reflective call and the class itself may not even be
on the class path. Relying on the fact that class names start with capital letter and packages
with lower case is heuristic.
It is recommended to use getShortClassName(String)
for cases when the class is an inner class and use this method for cases it is designed for.
Examples
return value input
""
(String)null
"Map.Entry"
java.util.Map.Entry.class.getName()
"Entry"
java.util.Map.Entry.class.getCanonicalName()
"ClassUtils"
"org.apache.commons.lang3.ClassUtils"
"ClassUtils[]"
"[Lorg.apache.commons.lang3.ClassUtils;"
"ClassUtils[][]"
"[[Lorg.apache.commons.lang3.ClassUtils;"
"ClassUtils[]"
"org.apache.commons.lang3.ClassUtils[]"
"ClassUtils[][]"
"org.apache.commons.lang3.ClassUtils[][]"
"int[]"
"[I"
"int[]"
int[].class.getCanonicalName()
"int[]"
int[].class.getName()
"int[][]"
"[[I"
"int[]"
"int[]"
"int[][]"
"int[][]"
Params: - canonicalName – the class name to get the short name for
Returns: the canonical name of the class without the package name or an empty string Since: 2.4
/**
* <p>Gets the canonical name minus the package name from a String.</p>
*
* <p>The string passed in is assumed to be a class name - it is not checked.</p>
*
* <p>Note that this method is mainly designed to handle the arrays and primitives properly.
* If the class is an inner class then the result value will not contain the outer classes.
* This way the behavior of this method is different from {@link #getShortClassName(String)}.
* The argument in that case is class name and not canonical name and the return value
* retains the outer classes.</p>
*
* <p>Note that there is no way to reliably identify the part of the string representing the
* package hierarchy and the part that is the outer class or classes in case of an inner class.
* Trying to find the class would require reflective call and the class itself may not even be
* on the class path. Relying on the fact that class names start with capital letter and packages
* with lower case is heuristic.</p>
*
* <p>It is recommended to use {@link #getShortClassName(String)} for cases when the class
* is an inner class and use this method for cases it is designed for.</p>
*
* <table>
* <caption>Examples</caption>
* <tr><td>return value</td><td>input</td></tr>
* <tr><td>{@code ""}</td><td>{@code (String)null}</td></tr>
* <tr><td>{@code "Map.Entry"}</td><td>{@code java.util.Map.Entry.class.getName()}</td></tr>
* <tr><td>{@code "Entry"}</td><td>{@code java.util.Map.Entry.class.getCanonicalName()}</td></tr>
* <tr><td>{@code "ClassUtils"}</td><td>{@code "org.apache.commons.lang3.ClassUtils"}</td></tr>
* <tr><td>{@code "ClassUtils[]"}</td><td>{@code "[Lorg.apache.commons.lang3.ClassUtils;"}</td></tr>
* <tr><td>{@code "ClassUtils[][]"}</td><td>{@code "[[Lorg.apache.commons.lang3.ClassUtils;"}</td></tr>
* <tr><td>{@code "ClassUtils[]"}</td><td>{@code "org.apache.commons.lang3.ClassUtils[]"}</td></tr>
* <tr><td>{@code "ClassUtils[][]"}</td><td>{@code "org.apache.commons.lang3.ClassUtils[][]"}</td></tr>
* <tr><td>{@code "int[]"}</td><td>{@code "[I"}</td></tr>
* <tr><td>{@code "int[]"}</td><td>{@code int[].class.getCanonicalName()}</td></tr>
* <tr><td>{@code "int[]"}</td><td>{@code int[].class.getName()}</td></tr>
* <tr><td>{@code "int[][]"}</td><td>{@code "[[I"}</td></tr>
* <tr><td>{@code "int[]"}</td><td>{@code "int[]"}</td></tr>
* <tr><td>{@code "int[][]"}</td><td>{@code "int[][]"}</td></tr>
* </table>
*
* @param canonicalName the class name to get the short name for
* @return the canonical name of the class without the package name or an empty string
* @since 2.4
*/
public static String getShortCanonicalName(final String canonicalName) {
return getShortClassName(getCanonicalName(canonicalName));
}
// Package name
// ----------------------------------------------------------------------
Gets the package name from the class name of an Object
.
Params: - object – the class to get the package name for, may be null
- valueIfNull – the value to return if null
Returns: the package name of the object, or the null value Since: 2.4
/**
* <p>Gets the package name from the class name of an {@code Object}.</p>
*
* @param object the class to get the package name for, may be null
* @param valueIfNull the value to return if null
* @return the package name of the object, or the null value
* @since 2.4
*/
public static String getPackageCanonicalName(final Object object, final String valueIfNull) {
if (object == null) {
return valueIfNull;
}
return getPackageCanonicalName(object.getClass().getName());
}
Gets the package name from the canonical name of a Class
.
Params: - cls – the class to get the package name for, may be
null
.
Returns: the package name or an empty string Since: 2.4
/**
* <p>Gets the package name from the canonical name of a {@code Class}.</p>
*
* @param cls the class to get the package name for, may be {@code null}.
* @return the package name or an empty string
* @since 2.4
*/
public static String getPackageCanonicalName(final Class<?> cls) {
if (cls == null) {
return StringUtils.EMPTY;
}
return getPackageCanonicalName(cls.getName());
}
Gets the package name from the class name.
The string passed in is assumed to be a class name - it is not checked.
If the class is in the default package, return an empty string.
Params: - name – the name to get the package name for, may be
null
Returns: the package name or an empty string Since: 2.4
/**
* <p>Gets the package name from the class name. </p>
*
* <p>The string passed in is assumed to be a class name - it is not checked.</p>
* <p>If the class is in the default package, return an empty string.</p>
*
* @param name the name to get the package name for, may be {@code null}
* @return the package name or an empty string
* @since 2.4
*/
public static String getPackageCanonicalName(final String name) {
return getPackageName(getCanonicalName(name));
}
Converts a given name of class into canonical format.
If name of class is not a name of array class it returns
unchanged name.
The method does not change the $
separators in case the class is inner class.
Example:
getCanonicalName("[I") = "int[]"
getCanonicalName("[Ljava.lang.String;") = "java.lang.String[]"
getCanonicalName("java.lang.String") = "java.lang.String"
Params: - className – the name of class
Returns: canonical form of class name Since: 2.4
/**
* <p>Converts a given name of class into canonical format.
* If name of class is not a name of array class it returns
* unchanged name.</p>
*
* <p>The method does not change the {@code $} separators in case
* the class is inner class.</p>
*
* <p>Example:
* <ul>
* <li>{@code getCanonicalName("[I") = "int[]"}</li>
* <li>{@code getCanonicalName("[Ljava.lang.String;") = "java.lang.String[]"}</li>
* <li>{@code getCanonicalName("java.lang.String") = "java.lang.String"}</li>
* </ul>
* </p>
*
* @param className the name of class
* @return canonical form of class name
* @since 2.4
*/
private static String getCanonicalName(String className) {
className = StringUtils.deleteWhitespace(className);
if (className == null) {
return null;
}
int dim = 0;
while (className.startsWith("[")) {
dim++;
className = className.substring(1);
}
if (dim < 1) {
return className;
}
if (className.startsWith("L")) {
className = className.substring(
1,
className.endsWith(";")
? className.length() - 1
: className.length());
} else {
if (!className.isEmpty()) {
className = reverseAbbreviationMap.get(className.substring(0, 1));
}
}
final StringBuilder canonicalClassNameBuffer = new StringBuilder(className);
for (int i = 0; i < dim; i++) {
canonicalClassNameBuffer.append("[]");
}
return canonicalClassNameBuffer.toString();
}
Gets an Iterable
that can iterate over a class hierarchy in ascending (subclass to superclass) order, excluding interfaces. Params: - type – the type to get the class hierarchy from
Returns: Iterable an Iterable over the class hierarchy of the given class Since: 3.2
/**
* Gets an {@link Iterable} that can iterate over a class hierarchy in ascending (subclass to superclass) order,
* excluding interfaces.
*
* @param type the type to get the class hierarchy from
* @return Iterable an Iterable over the class hierarchy of the given class
* @since 3.2
*/
public static Iterable<Class<?>> hierarchy(final Class<?> type) {
return hierarchy(type, Interfaces.EXCLUDE);
}
Gets an Iterable
that can iterate over a class hierarchy in ascending (subclass to superclass) order. Params: - type – the type to get the class hierarchy from
- interfacesBehavior – switch indicating whether to include or exclude interfaces
Returns: Iterable an Iterable over the class hierarchy of the given class Since: 3.2
/**
* Gets an {@link Iterable} that can iterate over a class hierarchy in ascending (subclass to superclass) order.
*
* @param type the type to get the class hierarchy from
* @param interfacesBehavior switch indicating whether to include or exclude interfaces
* @return Iterable an Iterable over the class hierarchy of the given class
* @since 3.2
*/
public static Iterable<Class<?>> hierarchy(final Class<?> type, final Interfaces interfacesBehavior) {
final Iterable<Class<?>> classes = () -> {
final MutableObject<Class<?>> next = new MutableObject<>(type);
return new Iterator<Class<?>>() {
@Override
public boolean hasNext() {
return next.getValue() != null;
}
@Override
public Class<?> next() {
final Class<?> result = next.getValue();
next.setValue(result.getSuperclass());
return result;
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
};
if (interfacesBehavior != Interfaces.INCLUDE) {
return classes;
}
return () -> {
final Set<Class<?>> seenInterfaces = new HashSet<>();
final Iterator<Class<?>> wrapped = classes.iterator();
return new Iterator<Class<?>>() {
Iterator<Class<?>> interfaces = Collections.<Class<?>>emptySet().iterator();
@Override
public boolean hasNext() {
return interfaces.hasNext() || wrapped.hasNext();
}
@Override
public Class<?> next() {
if (interfaces.hasNext()) {
final Class<?> nextInterface = interfaces.next();
seenInterfaces.add(nextInterface);
return nextInterface;
}
final Class<?> nextSuperclass = wrapped.next();
final Set<Class<?>> currentInterfaces = new LinkedHashSet<>();
walkInterfaces(currentInterfaces, nextSuperclass);
interfaces = currentInterfaces.iterator();
return nextSuperclass;
}
private void walkInterfaces(final Set<Class<?>> addTo, final Class<?> c) {
for (final Class<?> iface : c.getInterfaces()) {
if (!seenInterfaces.contains(iface)) {
addTo.add(iface);
}
walkInterfaces(addTo, iface);
}
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
};
};
}
}