it = primitiveTypeNames.iterator(); it.hasNext();) {
Class> primitiveClass = (Class>) it.next();
PRIMITIVE_TYPE_NAME_MAP.put(primitiveClass.getName(), primitiveClass);
}
}
private ClassUtils() {
}
/**
* Return the default ClassLoader to use: typically the thread context
* ClassLoader, if available; the ClassLoader that loaded the ClassUtils
* class will be used as fallback.
* Call this method if you intend to use the thread context ClassLoader
* in a scenario where you absolutely need a non-null ClassLoader reference:
* for example, for class path resource loading (but not necessarily for
* Class.forName
, which accepts a null
ClassLoader
* reference as well).
* @return the default ClassLoader (never null
)
* @see java.lang.Thread#getContextClassLoader()
*/
public static ClassLoader getDefaultClassLoader() {
if (DEFAULT_CLASSLOADER != null) {
return DEFAULT_CLASSLOADER;
}
ClassLoader cl = null;
try {
cl = Thread.currentThread().getContextClassLoader();
} catch (Throwable ex) {
// Cannot access thread context ClassLoader - falling back to system class loader...
}
if (cl == null) {
// No thread context class loader -> use class loader of this class.
cl = ClassUtils.class.getClassLoader();
}
return cl;
}
/**
* Override the thread context ClassLoader with the environment's bean ClassLoader
* if necessary, i.e. if the bean ClassLoader is not equivalent to the thread
* context ClassLoader already.
* @param classLoaderToUse the actual ClassLoader to use for the thread context
* @return the original thread context ClassLoader, or null
if not overridden
*/
public static ClassLoader overrideThreadContextClassLoader(ClassLoader classLoaderToUse) {
Thread currentThread = Thread.currentThread();
ClassLoader threadContextClassLoader = currentThread.getContextClassLoader();
if (classLoaderToUse != null && !classLoaderToUse.equals(threadContextClassLoader)) {
currentThread.setContextClassLoader(classLoaderToUse);
DEFAULT_CLASSLOADER = classLoaderToUse;
return threadContextClassLoader;
} else {
return null;
}
}
/**
* Determine whether the {@link Class} identified by the supplied name is present
* and can be loaded. Will return false
if either the class or
* one of its dependencies is not present or cannot be loaded.
* @param className the name of the class to check
* @return whether the specified class is present
*/
public static boolean isPresent(String className) {
return isPresent(className, getDefaultClassLoader());
}
/**
* Determine whether the {@link Class} identified by the supplied name is present
* and can be loaded. Will return false
if either the class or
* one of its dependencies is not present or cannot be loaded.
* @param className the name of the class to check
* @param classLoader the class loader to use
* (may be null
, which indicates the default class loader)
* @return whether the specified class is present
*/
public static boolean isPresent(String className, ClassLoader classLoader) {
try {
forName(className, classLoader);
return true;
} catch (Throwable ex) {
// Class or one of its dependencies is not present...
return false;
}
}
/**
* Replacement for Class.forName()
that also returns Class instances
* for primitives (like "int") and array class names (like "String[]").
*
Always uses the default class loader: that is, preferably the thread context
* class loader, or the ClassLoader that loaded the ClassUtils class as fallback.
* @param name the name of the Class
* @return Class instance for the supplied name
* @throws ClassNotFoundException if the class was not found
* @throws LinkageError if the class file could not be loaded
* @see Class#forName(String, boolean, ClassLoader)
* @see #getDefaultClassLoader()
*/
public static Class> forName(String name) throws ClassNotFoundException, LinkageError {
return forName(name, getDefaultClassLoader());
}
/**
* Replacement for Class.forName()
that also returns Class instances
* for primitives (like "int") and array class names (like "String[]").
* @param name the name of the Class
* @param classLoader the class loader to use
* (may be null
, which indicates the default class loader)
* @return Class instance for the supplied name
* @throws ClassNotFoundException if the class was not found
* @throws LinkageError if the class file could not be loaded
* @see Class#forName(String, boolean, ClassLoader)
*/
public static Class> forName(String name, ClassLoader classLoader) throws ClassNotFoundException, LinkageError {
if (name == null) {
throw new IllegalArgumentException("Name must not be null");
}
Class> clazz = resolvePrimitiveClassName(name);
if (clazz != null) {
return clazz;
}
// "java.lang.String[]" style arrays
if (name.endsWith(ARRAY_SUFFIX)) {
String elementClassName = name.substring(0, name.length() - ARRAY_SUFFIX.length());
Class> elementClass = forName(elementClassName, classLoader);
return Array.newInstance(elementClass, 0).getClass();
}
// "[Ljava.lang.String;" style arrays
int internalArrayMarker = name.indexOf(INTERNAL_ARRAY_PREFIX);
if (internalArrayMarker != -1 && name.endsWith(";")) {
String elementClassName = null;
if (internalArrayMarker == 0) {
elementClassName = name.substring(INTERNAL_ARRAY_PREFIX.length(), name.length() - 1);
} else if (name.startsWith("[")) {
elementClassName = name.substring(1);
}
Class> elementClass = forName(elementClassName, classLoader);
return Array.newInstance(elementClass, 0).getClass();
}
ClassLoader classLoaderToUse = classLoader;
if (classLoaderToUse == null) {
classLoaderToUse = getDefaultClassLoader();
}
return classLoaderToUse.loadClass(name);
}
/**
* Resolve the given class name into a Class instance. Supports
* primitives (like "int") and array class names (like "String[]").
*
This is effectively equivalent to the forName
* method with the same arguments, with the only difference being
* the exceptions thrown in case of class loading failure.
* @param className the name of the Class
* @param classLoader the class loader to use
* (may be null
, which indicates the default class loader)
* @return Class instance for the supplied name
* @throws IllegalArgumentException if the class name was not resolvable
* (that is, the class could not be found or the class file could not be loaded)
* @see #forName(String, ClassLoader)
*/
public static Class> resolveClassName(String className, ClassLoader classLoader) throws IllegalArgumentException {
try {
return forName(className, classLoader);
} catch (ClassNotFoundException ex) {
IllegalArgumentException iae = new IllegalArgumentException("Cannot find class [" + className + "]");
iae.initCause(ex);
throw iae;
} catch (LinkageError ex) {
IllegalArgumentException iae = new IllegalArgumentException(
"Error loading class [" + className + "]: problem with class file or dependent class.");
iae.initCause(ex);
throw iae;
}
}
/**
* Resolve the given class name as primitive class, if appropriate,
* according to the JVM's naming rules for primitive classes.
*
Also supports the JVM's internal class names for primitive arrays.
* Does not support the "[]" suffix notation for primitive arrays;
* this is only supported by {@link #forName}.
* @param name the name of the potentially primitive class
* @return the primitive class, or null
if the name does not denote
* a primitive class or primitive array class
*/
public static Class> resolvePrimitiveClassName(String name) {
Class> result = null;
// Most class names will be quite long, considering that they
// SHOULD sit in a package, so a length check is worthwhile.
if (name != null && name.length() <= 8) {
// Could be a primitive - likely.
result = (Class>)PRIMITIVE_TYPE_NAME_MAP.get(name);
}
return result;
}
/**
* Return the user-defined class for the given instance: usually simply
* the class of the given instance, but the original class in case of a
* CGLIB-generated subclass.
* @param instance the instance to check
* @return the user-defined class
*/
public static Class> getUserClass(Object instance) {
if (instance == null) {
throw new IllegalArgumentException("Instance must not be null");
}
return getUserClass(instance.getClass());
}
/**
* Return the user-defined class for the given class: usually simply the given
* class, but the original class in case of a CGLIB-generated subclass.
* @param clazz the class to check
* @return the user-defined class
*/
public static Class> getUserClass(Class> clazz) {
return (clazz != null && clazz.getName().indexOf(CGLIB_CLASS_SEPARATOR) != -1 ?
clazz.getSuperclass() : clazz);
}
/**
* Check whether the given class is cache-safe in the given context,
* i.e. whether it is loaded by the given ClassLoader or a parent of it.
* @param clazz the class to analyze
* @param classLoader the ClassLoader to potentially cache metadata in
*/
public static boolean isCacheSafe(Class> clazz, ClassLoader classLoader) {
if (clazz == null) {
throw new IllegalArgumentException("Class must not be null");
}
ClassLoader target = clazz.getClassLoader();
if (target == null) {
return false;
}
ClassLoader cur = classLoader;
if (cur == target) {
return true;
}
while (cur != null) {
cur = cur.getParent();
if (cur == target) {
return true;
}
}
return false;
}
/**
* Get the class name without the qualified package name.
* @param className the className to get the short name for
* @return the class name of the class without the package name
* @throws IllegalArgumentException if the className is empty
*/
public static String getShortName(String className) {
if (!StringUtils.hasLength(className)) {
throw new IllegalArgumentException("Class name must not be empty");
}
int lastDotIndex = className.lastIndexOf(PACKAGE_SEPARATOR);
int nameEndIndex = className.indexOf(CGLIB_CLASS_SEPARATOR);
if (nameEndIndex == -1) {
nameEndIndex = className.length();
}
String shortName = className.substring(lastDotIndex + 1, nameEndIndex);
shortName = shortName.replace(INNER_CLASS_SEPARATOR, PACKAGE_SEPARATOR);
return shortName;
}
/**
* Get the class name without the qualified package name.
* @param clazz the class to get the short name for
* @return the class name of the class without the package name
*/
public static String getShortName(Class> clazz) {
return getShortName(getQualifiedName(clazz));
}
/**
* Return the short string name of a Java class in decapitalized JavaBeans
* property format. Strips the outer class name in case of an inner class.
* @param clazz the class
* @return the short name rendered in a standard JavaBeans property format
* @see java.beans.Introspector#decapitalize(String)
*/
public static String getShortNameAsProperty(Class> clazz) {
String shortName = ClassUtils.getShortName(clazz);
int dotIndex = shortName.lastIndexOf('.');
shortName = (dotIndex != -1 ? shortName.substring(dotIndex + 1) : shortName);
return Introspector.decapitalize(shortName);
}
/**
* Determine the name of the class file, relative to the containing
* package: e.g. "String.class"
* @param clazz the class
* @return the file name of the ".class" file
*/
public static String getClassFileName(Class> clazz) {
if (clazz == null) {
throw new IllegalArgumentException("Class must not be null");
}
String className = clazz.getName();
int lastDotIndex = className.lastIndexOf(PACKAGE_SEPARATOR);
return className.substring(lastDotIndex + 1) + CLASS_FILE_SUFFIX;
}
/**
* Determine the name of the package of the given class:
* e.g. "java.lang" for the java.lang.String
class.
* @param clazz the class
* @return the package name, or the empty String if the class
* is defined in the default package
*/
public static String getPackageName(Class> clazz) {
if (clazz == null) {
throw new IllegalArgumentException("Class must not be null");
}
String className = clazz.getName();
int lastDotIndex = className.lastIndexOf(PACKAGE_SEPARATOR);
return (lastDotIndex != -1 ? className.substring(0, lastDotIndex) : "");
}
/**
* Return the qualified name of the given class: usually simply
* the class name, but component type class name + "[]" for arrays.
* @param clazz the class
* @return the qualified name of the class
*/
public static String getQualifiedName(Class> clazz) {
if (clazz == null) {
throw new IllegalArgumentException("Class must not be null");
}
if (clazz.isArray()) {
return getQualifiedNameForArray(clazz);
} else {
return clazz.getName();
}
}
/**
* Return the qualified name of the given method, consisting of
* fully qualified interface/class name + "." + method name.
* @param method the method
* @return the qualified name of the method
*/
public static String getQualifiedMethodName(Method method) {
if (method == null) {
throw new IllegalArgumentException("Method must not be null");
}
return method.getDeclaringClass().getName() + "." + method.getName();
}
/**
* Return a descriptive name for the given object's type: usually simply
* the class name, but component type class name + "[]" for arrays,
* and an appended list of implemented interfaces for JDK proxies.
* @param value the value to introspect
* @return the qualified name of the class
*/
public static String getDescriptiveType(Object value) {
if (value == null) {
return null;
}
Class> clazz = value.getClass();
if (Proxy.isProxyClass(clazz)) {
StringBuffer buf = new StringBuffer(clazz.getName());
buf.append(" implementing ");
Class>[] ifcs = clazz.getInterfaces();
for (int i = 0; i < ifcs.length; i++) {
buf.append(ifcs[i].getName());
if (i < ifcs.length - 1) {
buf.append(',');
}
}
return buf.toString();
} else if (clazz.isArray()) {
return getQualifiedNameForArray(clazz);
} else {
return clazz.getName();
}
}
/**
* Determine whether the given class has a constructor with the given signature.
*
Essentially translates NoSuchMethodException
to "false".
* @param clazz the clazz to analyze
* @param paramTypes the parameter types of the method
* @return whether the class has a corresponding constructor
* @see java.lang.Class#getMethod
*/
public static boolean hasConstructor(Class> clazz, Class>[] paramTypes) {
return (getConstructorIfAvailable(clazz, paramTypes) != null);
}
/**
* Determine whether the given class has a constructor with the given signature,
* and return it if available (else return null
).
*
Essentially translates NoSuchMethodException
to null
.
* @param clazz the clazz to analyze
* @param paramTypes the parameter types of the method
* @return the constructor, or null
if not found
* @see java.lang.Class#getConstructor
*/
public static Constructor> getConstructorIfAvailable(Class> clazz, Class>[] paramTypes) {
if (clazz == null) {
throw new IllegalArgumentException("Class must not be null");
}
try {
return clazz.getConstructor(paramTypes);
} catch (NoSuchMethodException ex) {
return null;
}
}
/**
* Determine all fields include private, protected and public
* @param clazz
* @param includeParent Determine parent class fields
* @return
*/
public static List getDeclaredFields(Class> clazz, boolean includeParent) {
List fieldList = new ArrayList();
getDeclaredFields(clazz, includeParent, fieldList);
return fieldList;
}
/**
* Check given field name is field of given class
* @param clazz
* @param fieldName
* @return
*/
public static boolean hasField(Class> clazz, String fieldName) {
return (getFieldIfAvaliable(clazz, fieldName) != null);
}
/**
* Determine whether the given class has a field with the given field name.
* @param clazz
* @param fieldName
* @return
*/
public static Field getFieldIfAvaliable(Class> clazz, String fieldName) {
if (clazz == null) {
throw new IllegalArgumentException("Class must not be null");
}
if (fieldName == null) {
throw new IllegalArgumentException("Method name must not be null");
}
try {
return clazz.getField(fieldName);
} catch (SecurityException e) {
return null;
} catch (NoSuchFieldException e) {
return null;
}
}
/**
* Determine whether the given class has a method with the given signature.
* Essentially translates NoSuchMethodException
to "false".
* @param clazz the clazz to analyze
* @param methodName the name of the method
* @param paramTypes the parameter types of the method
* @return whether the class has a corresponding method
* @see java.lang.Class#getMethod
*/
public static boolean hasMethod(Class> clazz, String methodName, Class>[] paramTypes) {
return (getMethodIfAvailable(clazz, methodName, paramTypes) != null);
}
/**
* Determine whether the given class has a method with the given signature,
* and return it if available (else return null
).
*
Essentially translates NoSuchMethodException
to null
.
* @param clazz the clazz to analyze
* @param methodName the name of the method
* @param paramTypes the parameter types of the method
* @return the method, or null
if not found
* @see java.lang.Class#getMethod
*/
public static Method getMethodIfAvailable(Class> clazz, String methodName, Class>[] paramTypes) {
if (clazz == null) {
throw new IllegalArgumentException("Class must not be null");
}
if (methodName == null) {
throw new IllegalArgumentException("Method name must not be null");
}
try {
return clazz.getMethod(methodName, paramTypes);
} catch (NoSuchMethodException ex) {
return null;
}
}
/**
* Return the number of methods with a given name (with any argument types),
* for the given class and/or its superclasses. Includes non-public methods.
* @param clazz the clazz to check
* @param methodName the name of the method
* @return the number of methods with the given name
*/
public static int getMethodCountForName(Class> clazz, String methodName) {
if (clazz == null) {
throw new IllegalArgumentException("Class must not be null");
}
if (methodName == null) {
throw new IllegalArgumentException("Method name must not be null");
}
int count = 0;
Method[] declaredMethods = clazz.getDeclaredMethods();
for (int i = 0; i < declaredMethods.length; i++) {
Method method = declaredMethods[i];
if (methodName.equals(method.getName())) {
count++;
}
}
Class>[] ifcs = clazz.getInterfaces();
for (int i = 0; i < ifcs.length; i++) {
count += getMethodCountForName(ifcs[i], methodName);
}
if (clazz.getSuperclass() != null) {
count += getMethodCountForName(clazz.getSuperclass(), methodName);
}
return count;
}
/**
* Does the given class and/or its superclasses at least have one or more
* methods (with any argument types)? Includes non-public methods.
* @param clazz the clazz to check
* @param methodName the name of the method
* @return whether there is at least one method with the given name
*/
public static boolean hasAtLeastOneMethodWithName(Class> clazz, String methodName) {
if (clazz == null) {
throw new IllegalArgumentException("Class must not be null");
}
if (methodName == null) {
throw new IllegalArgumentException("Method name must not be null");
}
Method[] declaredMethods = clazz.getDeclaredMethods();
for (int i = 0; i < declaredMethods.length; i++) {
Method method = declaredMethods[i];
if (method.getName().equals(methodName)) {
return true;
}
}
Class>[] ifcs = clazz.getInterfaces();
for (int i = 0; i < ifcs.length; i++) {
if (hasAtLeastOneMethodWithName(ifcs[i], methodName)) {
return true;
}
}
return (clazz.getSuperclass() != null && hasAtLeastOneMethodWithName(clazz.getSuperclass(), methodName));
}
/**
* Given a method, which may come from an interface, and a target class used
* in the current reflective invocation, find the corresponding target method
* if there is one. E.g. the method may be IFoo.bar()
and the
* target class may be DefaultFoo
. In this case, the method may be
* DefaultFoo.bar()
. This enables attributes on that method to be found.
*
NOTE: In contrast to {@link org.springframework.aop.support.AopUtils#getMostSpecificMethod},
* this method does not resolve Java 5 bridge methods automatically.
* Call {@link org.springframework.core.BridgeMethodResolver#findBridgedMethod}
* if bridge method resolution is desirable (e.g. for obtaining metadata from
* the original method definition).
* @param method the method to be invoked, which may come from an interface
* @param targetClass the target class for the current invocation.
* May be null
or may not even implement the method.
* @return the specific target method, or the original method if the
* targetClass
doesn't implement it or is null
* @see org.springframework.aop.support.AopUtils#getMostSpecificMethod
*/
public static Method getMostSpecificMethod(Method method, Class> targetClass) {
if (method != null && targetClass != null && !targetClass.equals(method.getDeclaringClass())) {
try {
method = targetClass.getMethod(method.getName(), method.getParameterTypes());
} catch (NoSuchMethodException ex) {
// Perhaps the target class doesn't implement this method:
// that's fine, just use the original method.
}
}
return method;
}
/**
* Return a static method of a class.
* @param methodName the static method name
* @param clazz the class which defines the method
* @param args the parameter types to the method
* @return the static method, or null
if no static method was found
* @throws IllegalArgumentException if the method name is blank or the clazz is null
*/
public static Method getStaticMethod(Class> clazz, String methodName, Class>[] args) {
if (clazz == null) {
throw new IllegalArgumentException("Class must not be null");
}
if (methodName == null) {
throw new IllegalArgumentException("Method name must not be null");
}
try {
Method method = clazz.getDeclaredMethod(methodName, args);
if ((method.getModifiers() & Modifier.STATIC) != 0) {
return method;
}
} catch (NoSuchMethodException ex) {
}
return null;
}
/**
* Check if the given class represents a primitive wrapper,
* i.e. Boolean, Byte, Character, Short, Integer, Long, Float, or Double.
* @param clazz the class to check
* @return whether the given class is a primitive wrapper class
*/
public static boolean isPrimitiveWrapper(Class> clazz) {
if (clazz == null) {
throw new IllegalArgumentException("Class must not be null");
}
return PRIMITIVE_WRAPPER_TYPE_MAP.containsKey(clazz);
}
/**
* Check if the given class represents a primitive (i.e. boolean, byte,
* char, short, int, long, float, or double) or a primitive wrapper
* (i.e. Boolean, Byte, Character, Short, Integer, Long, Float, or Double).
* @param clazz the class to check
* @return whether the given class is a primitive or primitive wrapper class
*/
public static boolean isPrimitiveOrWrapper(Class> clazz) {
if (clazz == null) {
throw new IllegalArgumentException("Class must not be null");
}
return (clazz.isPrimitive() || isPrimitiveWrapper(clazz));
}
/**
* Check if the given class represents an array of primitives,
* i.e. boolean, byte, char, short, int, long, float, or double.
* @param clazz the class to check
* @return whether the given class is a primitive array class
*/
public static boolean isPrimitiveArray(Class> clazz) {
if (clazz == null) {
throw new IllegalArgumentException("Class must not be null");
}
return (clazz.isArray() && clazz.getComponentType().isPrimitive());
}
/**
* Check if the given class represents an array of primitive wrappers,
* i.e. Boolean, Byte, Character, Short, Integer, Long, Float, or Double.
* @param clazz the class to check
* @return whether the given class is a primitive wrapper array class
*/
public static boolean isPrimitiveWrapperArray(Class> clazz) {
if (clazz == null) {
throw new IllegalArgumentException("Class must not be null");
}
return (clazz.isArray() && isPrimitiveWrapper(clazz.getComponentType()));
}
/**
* Check if the right-hand side type may be assigned to the left-hand side
* type, assuming setting by reflection. Considers primitive wrapper
* classes as assignable to the corresponding primitive types.
* @param lhsType the target type
* @param rhsType the value type that should be assigned to the target type
* @return if the target type is assignable from the value type
* @see TypeUtils#isAssignable
*/
public static boolean isAssignable(Class> lhsType, Class> rhsType) {
if (lhsType == null) {
throw new IllegalArgumentException("Left-hand side type must not be null");
}
if (rhsType == null) {
throw new IllegalArgumentException("Right-hand side type must not be null");
}
return (lhsType.isAssignableFrom(rhsType) ||
lhsType.equals(PRIMITIVE_WRAPPER_TYPE_MAP.get(rhsType)));
}
/**
* Determine if the given type is assignable from the given value,
* assuming setting by reflection. Considers primitive wrapper classes
* as assignable to the corresponding primitive types.
* @param type the target type
* @param value the value that should be assigned to the type
* @return if the type is assignable from the value
*/
public static boolean isAssignableValue(Class> type, Object value) {
if (type == null) {
throw new IllegalArgumentException("Type must not be null");
}
return (value != null ? isAssignable(type, value.getClass()) : !type.isPrimitive());
}
/**
* Convert a "/"-based resource path to a "."-based fully qualified class name.
* @param resourcePath the resource path pointing to a class
* @return the corresponding fully qualified class name
*/
public static String convertResourcePathToClassName(String resourcePath) {
return resourcePath.replace('/', '.');
}
/**
* Convert a "."-based fully qualified class name to a "/"-based resource path.
* @param className the fully qualified class name
* @return the corresponding resource path, pointing to the class
*/
public static String convertClassNameToResourcePath(String className) {
return className.replace('.', '/');
}
/**
* Return a path suitable for use with ClassLoader.getResource
* (also suitable for use with Class.getResource
by prepending a
* slash ('/') to the return value. Built by taking the package of the specified
* class file, converting all dots ('.') to slashes ('/'), adding a trailing slash
* if necesssary, and concatenating the specified resource name to this.
* As such, this function may be used to build a path suitable for
* loading a resource file that is in the same package as a class file,
* although {@link org.springframework.core.io.ClassPathResource} is usually
* even more convenient.
* @param clazz the Class whose package will be used as the base
* @param resourceName the resource name to append. A leading slash is optional.
* @return the built-up resource path
* @see java.lang.ClassLoader#getResource
* @see java.lang.Class#getResource
*/
public static String addResourcePathToPackagePath(Class> clazz, String resourceName) {
if (resourceName == null) {
throw new IllegalArgumentException("Resource name must not be null");
}
if (!resourceName.startsWith("/")) {
return classPackageAsResourcePath(clazz) + "/" + resourceName;
}
return classPackageAsResourcePath(clazz) + resourceName;
}
/**
* Given an input class object, return a string which consists of the
* class's package name as a pathname, i.e., all dots ('.') are replaced by
* slashes ('/'). Neither a leading nor trailing slash is added. The result
* could be concatenated with a slash and the name of a resource, and fed
* directly to ClassLoader.getResource()
. For it to be fed to
* Class.getResource
instead, a leading slash would also have
* to be prepended to the returned value.
* @param clazz the input class. A null
value or the default
* (empty) package will result in an empty string ("") being returned.
* @return a path which represents the package name
* @see ClassLoader#getResource
* @see Class#getResource
*/
public static String classPackageAsResourcePath(Class> clazz) {
if (clazz == null) {
return "";
}
String className = clazz.getName();
int packageEndIndex = className.lastIndexOf('.');
if (packageEndIndex == -1) {
return "";
}
String packageName = className.substring(0, packageEndIndex);
return packageName.replace('.', '/');
}
/**
* Build a String that consists of the names of the classes/interfaces
* in the given array.
*
Basically like AbstractCollection.toString()
, but stripping
* the "class "/"interface " prefix before every class name.
* @param classes a Collection of Class objects (may be null
)
* @return a String of form "[com.foo.Bar, com.foo.Baz]"
* @see java.util.AbstractCollection#toString()
*/
public static String classNamesToString(Class>[] classes) {
return classNamesToString(Arrays.asList(classes));
}
/**
* Build a String that consists of the names of the classes/interfaces
* in the given collection.
*
Basically like AbstractCollection.toString()
, but stripping
* the "class "/"interface " prefix before every class name.
* @param classes a Collection of Class objects (may be null
)
* @return a String of form "[com.foo.Bar, com.foo.Baz]"
* @see java.util.AbstractCollection#toString()
*/
public static String classNamesToString(Collection> classes) {
if (CollectionUtils.isEmpty(classes)) {
return "[]";
}
StringBuffer sb = new StringBuffer("[");
for (Iterator> it = classes.iterator(); it.hasNext(); ) {
Class> clazz = (Class>) it.next();
sb.append(clazz.getName());
if (it.hasNext()) {
sb.append(", ");
}
}
sb.append("]");
return sb.toString();
}
/**
* Return all interfaces that the given instance implements as array,
* including ones implemented by superclasses.
* @param instance the instance to analyse for interfaces
* @return all interfaces that the given instance implements as array
*/
public static Class>[] getAllInterfaces(Object instance) {
if (instance == null) {
throw new IllegalArgumentException("Instance must not be null");
}
return getAllInterfacesForClass(instance.getClass());
}
/**
* Return all interfaces that the given class implements as array,
* including ones implemented by superclasses.
*
If the class itself is an interface, it gets returned as sole interface.
* @param clazz the class to analyse for interfaces
* @return all interfaces that the given object implements as array
*/
public static Class>[] getAllInterfacesForClass(Class> clazz) {
return getAllInterfacesForClass(clazz, null);
}
/**
* Return all interfaces that the given class implements as array,
* including ones implemented by superclasses.
*
If the class itself is an interface, it gets returned as sole interface.
* @param clazz the class to analyse for interfaces
* @param classLoader the ClassLoader that the interfaces need to be visible in
* (may be null
when accepting all declared interfaces)
* @return all interfaces that the given object implements as array
*/
public static Class>[] getAllInterfacesForClass(Class> clazz, ClassLoader classLoader) {
if (clazz == null) {
throw new IllegalArgumentException("Class must not be null");
}
if (clazz.isInterface()) {
return new Class[] {clazz};
}
List interfaces = new ArrayList();
while (clazz != null) {
for (int i = 0; i < clazz.getInterfaces().length; i++) {
Class> ifc = clazz.getInterfaces()[i];
if (!interfaces.contains(ifc) &&
(classLoader == null || isVisible(ifc, classLoader))) {
interfaces.add(ifc);
}
}
clazz = clazz.getSuperclass();
}
return (Class[]) interfaces.toArray(new Class[interfaces.size()]);
}
/**
* Return all interfaces that the given instance implements as Set,
* including ones implemented by superclasses.
* @param instance the instance to analyse for interfaces
* @return all interfaces that the given instance implements as Set
*/
public static Set> getAllInterfacesAsSet(Object instance) {
if (instance == null) {
throw new IllegalArgumentException("Instance must not be null");
}
return getAllInterfacesForClassAsSet(instance.getClass());
}
/**
* Return all interfaces that the given class implements as Set,
* including ones implemented by superclasses.
* If the class itself is an interface, it gets returned as sole interface.
* @param clazz the class to analyse for interfaces
* @return all interfaces that the given object implements as Set
*/
public static Set> getAllInterfacesForClassAsSet(Class> clazz) {
return getAllInterfacesForClassAsSet(clazz, null);
}
/**
* Return all interfaces that the given class implements as Set,
* including ones implemented by superclasses.
*
If the class itself is an interface, it gets returned as sole interface.
* @param clazz the class to analyse for interfaces
* @param classLoader the ClassLoader that the interfaces need to be visible in
* (may be null
when accepting all declared interfaces)
* @return all interfaces that the given object implements as Set
*/
public static Set> getAllInterfacesForClassAsSet(Class> clazz, ClassLoader classLoader) {
if (clazz == null) {
throw new IllegalArgumentException("Class must not be null");
}
if (clazz.isInterface()) {
return Collections.singleton(clazz);
}
Set interfaces = new LinkedHashSet();
while (clazz != null) {
for (int i = 0; i < clazz.getInterfaces().length; i++) {
Class> ifc = clazz.getInterfaces()[i];
if (classLoader == null || isVisible(ifc, classLoader)) {
interfaces.add(ifc);
}
}
clazz = clazz.getSuperclass();
}
return interfaces;
}
/**
* Create a composite interface Class for the given interfaces,
* implementing the given interfaces in one single Class.
* This implementation builds a JDK proxy class for the given interfaces.
* @param interfaces the interfaces to merge
* @param classLoader the ClassLoader to create the composite Class in
* @return the merged interface as Class
* @see java.lang.reflect.Proxy#getProxyClass
*/
public static Class> createCompositeInterface(Class>[] interfaces, ClassLoader classLoader) {
if (ObjectUtils.isEmpty(interfaces)) {
throw new IllegalArgumentException("Interfaces must not be empty");
}
if (classLoader == null) {
throw new IllegalArgumentException("ClassLoader must not be null");
}
return Proxy.getProxyClass(classLoader, interfaces);
}
/**
* Check whether the given class is visible in the given ClassLoader.
* @param clazz the class to check (typically an interface)
* @param classLoader the ClassLoader to check against (may be null
,
* in which case this method will always return true
)
*/
public static boolean isVisible(Class> clazz, ClassLoader classLoader) {
if (classLoader == null) {
return true;
}
try {
Class> actualClass = classLoader.loadClass(clazz.getName());
return (clazz == actualClass);
// Else: different interface class found...
} catch (ClassNotFoundException ex) {
// No interface class found...
return false;
}
}
/**
* Build a nice qualified name for an array:
* component type class name + "[]".
* @param clazz the array class
* @return a qualified name for the array class
*/
private static String getQualifiedNameForArray(Class> clazz) {
StringBuffer buffer = new StringBuffer();
while (clazz.isArray()) {
clazz = clazz.getComponentType();
buffer.append(ClassUtils.ARRAY_SUFFIX);
}
buffer.insert(0, clazz.getName());
return buffer.toString();
}
private static void getDeclaredFields(Class> clazz, boolean includeParent, List fieldList) {
if (fieldList == null) {
return;
}
if (includeParent && clazz.getSuperclass() != null) {
getDeclaredFields(clazz.getSuperclass(), includeParent, fieldList);
}
for (Field field : clazz.getDeclaredFields()) {
fieldList.add(field);
}
}
}