/*
* 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 behaviour 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 behaviour 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 {
INCLUDE, EXCLUDE
}
The package separator character: '.' == .
.
/**
* The package separator character: <code>'.' == {@value}</code>.
*/
public static final char PACKAGE_SEPARATOR_CHAR = '.';
The package separator String: "."
.
/**
* The package separator String: <code>"."</code>.
*/
public static final String PACKAGE_SEPARATOR = String.valueOf(PACKAGE_SEPARATOR_CHAR);
The inner class separator character: '$' == $
.
/**
* The inner class separator character: <code>'$' == {@value}</code>.
*/
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
/**
* 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 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 class name of the object without the package name, or the null value
/**
* <p>Gets the class 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 class name of the object without the package name, or the null value
*/
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
.
Consider using the Java 5 API Class.getSimpleName()
instead. The one known difference is that this code will return "Map.Entry"
while the java.lang.Class
variant will simply return "Entry"
.
Params: - cls – the class to get the short name for.
Returns: the class name without the package name or an empty string
/**
* <p>Gets the class name minus the package name from a {@code Class}.</p>
*
* <p>Consider using the Java 5 API {@link Class#getSimpleName()} instead.
* The one known difference is that this code will return {@code "Map.Entry"} while
* the {@code java.lang.Class} variant will simply return {@code "Entry"}. </p>
*
* @param cls the class to get the short name for.
* @return the class name without the package name or an empty string
*/
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.
Note that this method differs from Class.getSimpleName() in that this will return "Map.Entry"
whilst the java.lang.Class
variant will simply return "Entry"
.
Params: - className – the className to get the short name for
Returns: the class name of the class without the package name or an empty string
/**
* <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.</p>
* <p>Note that this method differs from Class.getSimpleName() in that this will
* return {@code "Map.Entry"} whilst the {@code java.lang.Class} variant will simply
* return {@code "Entry"}. </p>
*
* @param className the className to get the short name for
* @return the class name of the class without the package name or an empty string
*/
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 aClass.getSimpleName()
Params: - cls – the class for which to get the simple name; may be null
See Also: Returns: the simple class name. Since: 3.0
/**
* <p>Null-safe version of <code>aClass.getSimpleName()</code></p>
*
* @param cls the class for which to get the simple name; may be null
* @return the simple class name.
* @since 3.0
* @see Class#getSimpleName()
*/
public static String getSimpleName(final Class<?> cls) {
return getSimpleName(cls, StringUtils.EMPTY);
}
Null-safe version of aClass.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
Since: 3.0
/**
* <p>Null-safe version of <code>aClass.getSimpleName()</code></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}
* @since 3.0
* @see Class#getSimpleName()
*/
public static String getSimpleName(final Class<?> cls, String valueIfNull) {
return cls == null ? valueIfNull : cls.getSimpleName();
}
Null-safe version of aClass.getSimpleName()
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 Since: 3.7
/**
* <p>Null-safe version of <code>aClass.getSimpleName()</code></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
* @since 3.7
* @see Class#getSimpleName()
*/
public static String getSimpleName(final Object object) {
return getSimpleName(object, StringUtils.EMPTY);
}
Null-safe version of aClass.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
Since: 3.0
/**
* <p>Null-safe version of <code>aClass.getSimpleName()</code></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</code> is <code>null</code>
* @return the simple class name or {@code valueIfNull}
* @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 Class.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. Since: 3.7
/**
* <p>Null-safe version of <code>Class.getName()</code></p>
*
* @param cls the class 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 Class<?> cls) {
return getName(cls, StringUtils.EMPTY);
}
Null-safe version of aClass.getName()
Params: - cls – the class for which to get the class name; may be null
- valueIfNull – the return value if
cls
is null
See Also: Returns: the class name or valueIfNull
Since: 3.7
/**
* <p>Null-safe version of <code>aClass.getName()</code></p>
*
* @param cls the class for which to get the class name; may be null
* @param valueIfNull the return value if <code>cls</code> is <code>null</code>
* @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 Class.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>Class.getName()</code></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 aClass.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>aClass.getSimpleName()</code></p>
*
* @param object the object for which to get the class name; may be null
* @param valueIfNull the value to return if <code>object</code> is <code>null</code>
* @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
- len – 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 len 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 len) {
if (cls == null) {
return StringUtils.EMPTY;
}
return getAbbreviatedName(cls.getName(), len);
}
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 following table illustrates the algorithm:
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"
Params: - className – the className to get the abbreviated name for, may be
null
- len – the desired length of the abbreviated name
Throws: - IllegalArgumentException – if len <= 0
Returns: the abbreviated name or an empty string 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.</p>
*
* <p>The following table illustrates the algorithm:</p>
* <table summary="abbreviation examples">
* <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>
* </table>
* @param className the className to get the abbreviated name for, may be {@code null}
* @param len the desired length of the abbreviated name
* @return the abbreviated name or an empty string
* @throws IllegalArgumentException if len <= 0
* @since 3.4
*/
public static String getAbbreviatedName(final String className, final int len) {
if (len <= 0) {
throw new IllegalArgumentException("len must be > 0");
}
if (className == null) {
return StringUtils.EMPTY;
}
int availableSpace = len;
final int packageLevels = StringUtils.countMatches(className, '.');
final String[] output = new String[packageLevels + 1];
int endIndex = className.length() - 1;
for (int level = packageLevels; level >= 0; level--) {
final int startIndex = className.lastIndexOf('.', endIndex);
final String part = className.substring(startIndex + 1, endIndex + 1);
availableSpace -= part.length();
if (level > 0) {
// all elements except top level require an additional char space
availableSpace--;
}
if (level == packageLevels) {
// ClassName is always complete
output[level] = part;
} else {
if (availableSpace > 0) {
output[level] = part;
} else {
// if no space is left still the first char is used
output[level] = part.substring(0, 1);
}
}
endIndex = startIndex - 1;
}
return StringUtils.join(output, '.');
}
// 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);
}
Get the interfaces for the specified class.
Params: - cls – the class to look up, may be
null
- interfacesFound – the
Set
of interfaces for the class
/**
* Get 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, SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_1_5));
}
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, SystemUtils.isJavaVersionAtLeast(JavaVersion.JAVA_1_5));
}
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 SecurityException, 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 canonical name - it is not checked.
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 canonical name - it is not checked.</p>
*
* @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 ClassUtils.getShortClassName(getCanonicalName(canonicalName));
}
// Package name
// ----------------------------------------------------------------------
Gets the package name from the canonical 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 canonical 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 canonical name.
The string passed in is assumed to be a canonical name - it is not checked.
If the class is unpackaged, return an empty string.
Params: - canonicalName – the canonical 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 canonical name. </p>
*
* <p>The string passed in is assumed to be a canonical name - it is not checked.</p>
* <p>If the class is unpackaged, return an empty string.</p>
*
* @param canonicalName the canonical 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 canonicalName) {
return ClassUtils.getPackageName(getCanonicalName(canonicalName));
}
Converts a given name of class into canonical format.
If name of class is not a name of array class it returns
unchanged name.
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>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.length() > 0) {
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();
}
Get 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
/**
* Get 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);
}
Get 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
/**
* Get 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 = new Iterable<Class<?>>() {
@Override
public Iterator<Class<?>> iterator() {
final MutableObject<Class<?>> next = new MutableObject<Class<?>>(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 new Iterable<Class<?>>() {
@Override
public Iterator<Class<?>> iterator() {
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();
}
};
}
};
}
}