http://git-wip-us.apache.org/repos/asf/incubator-tamaya/blob/95885781/core/src/main/java/org/apache/tamaya/core/util/ClassUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/tamaya/core/util/ClassUtils.java
b/core/src/main/java/org/apache/tamaya/core/util/ClassUtils.java
index 98c67ba..9e7e6d9 100644
--- a/core/src/main/java/org/apache/tamaya/core/util/ClassUtils.java
+++ b/core/src/main/java/org/apache/tamaya/core/util/ClassUtils.java
@@ -34,1041 +34,1069 @@ import java.util.Objects;
import java.util.Set;
/**
-* Miscellaneous class utility methods.
-* Mainly for internal use within the framework.
-*
-* @author Juergen Hoeller
-* @author Keith Donald
-* @author Rob Harrop
-* @author Sam Brannen
-* @since 1.1
-*/
+ * Miscellaneous class utility methods.
+ * Mainly for internal use within the framework.
+ *
+ * @author Juergen Hoeller
+ * @author Keith Donald
+ * @author Rob Harrop
+ * @author Sam Brannen
+ * @since 1.1
+ */
public final class ClassUtils {
- /** Suffix for array class names: "[]" */
- public static final String ARRAY_SUFFIX = "[]";
-
- /** Prefix for internal array class names: "[" */
- private static final String INTERNAL_ARRAY_PREFIX = "[";
-
- /** Prefix for internal non-primitive array class names: "[L" */
- private static final String NON_PRIMITIVE_ARRAY_PREFIX = "[L";
-
- /** The package separator character '.' */
- private static final char PACKAGE_SEPARATOR = '.';
-
- /** The path separator character '/' */
- private static final char PATH_SEPARATOR = '/';
-
- /** The inner class separator character '$' */
- private static final char INNER_CLASS_SEPARATOR = '$';
-//
-// /** The CGLIB class separator character "$$" */
-// public static final String CGLIB_CLASS_SEPARATOR = "$$";
-//
-// /** The ".class" file suffix */
-// public static final String CLASS_FILE_SUFFIX = ".class";
-//
-
- /**
- * Map with primitive wrapper type as key and corresponding primitive
- * type as keys, for example: Integer.class -> int.class.
- */
- private static final Map<Class<?>, Class<?>> primitiveWrapperTypeMap =
new HashMap<>(8);
-
- /**
- * Map with primitive type as key and corresponding wrapper
- * type as keys, for example: int.class -> Integer.class.
- */
- private static final Map<Class<?>, Class<?>> primitiveTypeToWrapperMap
= new HashMap<>(8);
-
- /**
- * Map with primitive type name as key and corresponding primitive
- * type as keys, for example: "int" -> "int.class".
- */
- private static final Map<String, Class<?>> primitiveTypeNameMap = new
HashMap<>(32);
-//
-// /**
-// * Map with common "java.lang" class name as key and corresponding
Class as keys.
-// * Primarily for efficient deserialization current remote invocations.
-// */
-// private static final Map<String, Class<?>> commonClassCache = new
HashMap<String, Class<?>>(32);
-//
-//
- static {
- primitiveWrapperTypeMap.put(Boolean.class, boolean.class);
- primitiveWrapperTypeMap.put(Byte.class, byte.class);
- primitiveWrapperTypeMap.put(Character.class, char.class);
- primitiveWrapperTypeMap.put(Double.class, double.class);
- primitiveWrapperTypeMap.put(Float.class, float.class);
- primitiveWrapperTypeMap.put(Integer.class, int.class);
- primitiveWrapperTypeMap.put(Long.class, long.class);
- primitiveWrapperTypeMap.put(Short.class, short.class);
-
- for (Map.Entry<Class<?>, Class<?>> entry :
primitiveWrapperTypeMap.entrySet()) {
- primitiveTypeToWrapperMap.put(entry.getValue(),
entry.getKey());
-// registerCommonClasses(entry.getKey());
- }
-
- Set<Class<?>> primitiveTypes = new HashSet<>(32);
- primitiveTypes.addAll(primitiveWrapperTypeMap.values());
- primitiveTypes.addAll(Arrays.asList(new Class<?>[] {
- boolean[].class, byte[].class, char[].class,
double[].class,
- float[].class, int[].class, long[].class,
short[].class}));
- primitiveTypes.add(void.class);
- for (Class<?> primitiveType : primitiveTypes) {
- primitiveTypeNameMap.put(primitiveType.getName(),
primitiveType);
- }
- }
-
- 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.
- * <p>Call this method if you intend to use the thread context
ClassLoader
- * in a scenario where you clearly prefer a non-null ClassLoader
reference:
- * for example, for class path resource loading (but not necessarily for
- * {@code Class.forName}, which accepts a {@code null} ClassLoader
- * reference as well).
- * @return the default ClassLoader (only {@code null} if even the system
- * ClassLoader isn't accessible)
- * @see Thread#getContextClassLoader()
- * @see ClassLoader#getSystemClassLoader()
- */
- public static ClassLoader getDefaultClassLoader() {
- ClassLoader cl = null;
- try {
- cl = Thread.currentThread().getContextClassLoader();
- }
- catch (Throwable ex) {
- // Cannot access thread context ClassLoader - falling
back...
- }
- if (cl == null) {
- // No thread context class loader -> use class loader
current this class.
- cl = ClassUtils.class.getClassLoader();
- if (cl == null) {
- // getClassLoader() returning null indicates
the bootstrap ClassLoader
- try {
- cl = ClassLoader.getSystemClassLoader();
- }
- catch (Throwable ex) {
- // Cannot access system ClassLoader -
oh well, maybe the caller can live with null...
- }
- }
- }
- return cl;
- }
-
- /**
- * Replacement for {@code Class.forName()} that also returns Class
instances
- * for primitives (e.g. "int") and array class names (e.g. "String[]").
- * Furthermore, it is also capable current resolving inner class names
in Java source
- * style (e.g. "java.lang.Thread.State" instead current
"java.lang.Thread$State").
- * @param name the name current the Class
- * @param classLoader the class loader to use
- * (may be {@code 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 {
- Objects.requireNonNull(name, "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
- if (name.startsWith(NON_PRIMITIVE_ARRAY_PREFIX) &&
name.endsWith(";")) {
- String elementName =
name.substring(NON_PRIMITIVE_ARRAY_PREFIX.length(), name.length() - 1);
- Class<?> elementClass = forName(elementName,
classLoader);
- return Array.newInstance(elementClass, 0).getClass();
- }
-
- // "[[I" or "[[Ljava.lang.String;" style arrays
- if (name.startsWith(INTERNAL_ARRAY_PREFIX)) {
- String elementName =
name.substring(INTERNAL_ARRAY_PREFIX.length());
- Class<?> elementClass = forName(elementName,
classLoader);
- return Array.newInstance(elementClass, 0).getClass();
- }
-
- ClassLoader clToUse = classLoader;
- if (clToUse == null) {
- clToUse = getDefaultClassLoader();
- }
- try {
- return (clToUse != null ? clToUse.loadClass(name) :
Class.forName(name));
- }
- catch (ClassNotFoundException ex) {
- int lastDotIndex = name.lastIndexOf(PACKAGE_SEPARATOR);
- if (lastDotIndex != -1) {
- String innerClassName =
- name.substring(0, lastDotIndex)
+ INNER_CLASS_SEPARATOR + name.substring(lastDotIndex + 1);
- try {
- return (clToUse != null ?
clToUse.loadClass(innerClassName) : Class.forName(innerClassName));
- }
- catch (ClassNotFoundException ex2) {
- // Swallow - let original exception get
through
- }
- }
- throw ex;
- }
- }
-
-
- /**
- * Resolve the given class name as primitive class, if appropriate,
- * according to the JVM's naming rules for primitive classes.
- * <p>Also supports the JVM's internal class names for primitive arrays.
- * Does <i>not</i> support the "[]" suffix notation for primitive
arrays;
- * this is only supported by {@link #forName(String, ClassLoader)}.
- * @param name the name current the potentially primitive class
- * @return the primitive class, or {@code 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 = primitiveTypeNameMap.get(name);
- }
- return result;
- }
-
- /**
- * Determine whether the {@link Class} identified by the supplied name
is present
- * and can be loaded. Will return {@code false} if either the class or
- * one current its dependencies is not present or cannot be loaded.
- * @param className the name current the class to check
- * @param classLoader the class loader to use
- * (may be {@code 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 current its dependencies is not
present...
- return false;
- }
- }
-
-
- /**
- * 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
current it.
- * @param clazz the class to analyze
- * @param classLoader the ClassLoader to potentially cache metadata in
- */
- public static boolean isCacheSafe(Class<?> clazz, ClassLoader
classLoader) {
+ /**
+ * Suffix for array class names: "[]"
+ */
+ public static final String ARRAY_SUFFIX = "[]";
+
+ /**
+ * Prefix for internal array class names: "["
+ */
+ private static final String INTERNAL_ARRAY_PREFIX = "[";
+
+ /**
+ * Prefix for internal non-primitive array class names: "[L"
+ */
+ private static final String NON_PRIMITIVE_ARRAY_PREFIX = "[L";
+
+ /**
+ * The package separator character '.'
+ */
+ private static final char PACKAGE_SEPARATOR = '.';
+
+ /**
+ * The path separator character '/'
+ */
+ private static final char PATH_SEPARATOR = '/';
+
+ /**
+ * The inner class separator character '$'
+ */
+ private static final char INNER_CLASS_SEPARATOR = '$';
+
+ /**
+ * Map with primitive wrapper type as key and corresponding primitive
+ * type as keys, for example: Integer.class -> int.class.
+ */
+ private static final Map<Class<?>, Class<?>> PRIMITIVE_WRAPPER_TYPE_MAP =
new HashMap<>(8);
+
+ /**
+ * Map with primitive type as key and corresponding wrapper
+ * type as keys, for example: int.class -> Integer.class.
+ */
+ private static final Map<Class<?>, Class<?>> PRIMITIVE_TYPE_TO_WRAPPER_MAP
= new HashMap<>(8);
+
+ /**
+ * Map with primitive type name as key and corresponding primitive
+ * type as keys, for example: "int" -> "int.class".
+ */
+ private static final Map<String, Class<?>> PRIMITIVE_TYPE_NAME_MAP = new
HashMap<>(32);
+
+
+ static {
+ PRIMITIVE_WRAPPER_TYPE_MAP.put(Boolean.class, boolean.class);
+ PRIMITIVE_WRAPPER_TYPE_MAP.put(Byte.class, byte.class);
+ PRIMITIVE_WRAPPER_TYPE_MAP.put(Character.class, char.class);
+ PRIMITIVE_WRAPPER_TYPE_MAP.put(Double.class, double.class);
+ PRIMITIVE_WRAPPER_TYPE_MAP.put(Float.class, float.class);
+ PRIMITIVE_WRAPPER_TYPE_MAP.put(Integer.class, int.class);
+ PRIMITIVE_WRAPPER_TYPE_MAP.put(Long.class, long.class);
+ PRIMITIVE_WRAPPER_TYPE_MAP.put(Short.class, short.class);
+
+ for (Map.Entry<Class<?>, Class<?>> entry :
PRIMITIVE_WRAPPER_TYPE_MAP.entrySet()) {
+ PRIMITIVE_TYPE_TO_WRAPPER_MAP.put(entry.getValue(),
entry.getKey());
+ }
+
+ Set<Class<?>> primitiveTypes = new HashSet<>(32);
+ primitiveTypes.addAll(PRIMITIVE_WRAPPER_TYPE_MAP.values());
+ primitiveTypes.addAll(Arrays.asList(new Class<?>[]{
+ boolean[].class, byte[].class, char[].class, double[].class,
+ float[].class, int[].class, long[].class, short[].class}));
+ primitiveTypes.add(void.class);
+ for (Class<?> primitiveType : primitiveTypes) {
+ PRIMITIVE_TYPE_NAME_MAP.put(primitiveType.getName(),
primitiveType);
+ }
+ }
+
+ /**
+ * Private singleton constructor.
+ */
+ 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.
+ * <p>Call this method if you intend to use the thread context ClassLoader
+ * in a scenario where you clearly prefer a non-null ClassLoader reference:
+ * for example, for class path resource loading (but not necessarily for
+ * {@code Class.forName}, which accepts a {@code null} ClassLoader
+ * reference as well).
+ *
+ * @return the default ClassLoader (only {@code null} if even the system
+ * ClassLoader isn't accessible)
+ * @see Thread#getContextClassLoader()
+ * @see ClassLoader#getSystemClassLoader()
+ */
+ public static ClassLoader getDefaultClassLoader() {
+ ClassLoader cl = null;
+ try {
+ cl = Thread.currentThread().getContextClassLoader();
+ } catch (Throwable ex) {
+ // Cannot access thread context ClassLoader - falling back...
+ }
+ if (cl == null) {
+ // No thread context class loader -> use class loader current this
class.
+ cl = ClassUtils.class.getClassLoader();
+ if (cl == null) {
+ // getClassLoader() returning null indicates the bootstrap
ClassLoader
+ try {
+ cl = ClassLoader.getSystemClassLoader();
+ } catch (Throwable ex) {
+ // Cannot access system ClassLoader - oh well, maybe the
caller can live with null...
+ }
+ }
+ }
+ return cl;
+ }
+
+ /**
+ * Replacement for {@code Class.forName()} that also returns Class
instances
+ * for primitives (e.g. "int") and array class names (e.g. "String[]").
+ * Furthermore, it is also capable current resolving inner class names in
Java source
+ * style (e.g. "java.lang.Thread.State" instead current
"java.lang.Thread$State").
+ *
+ * @param name the name current the Class
+ * @param classLoader the class loader to use
+ * (may be {@code 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 {
+ Objects.requireNonNull(name, "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
+ if (name.startsWith(NON_PRIMITIVE_ARRAY_PREFIX) && name.endsWith(";"))
{
+ String elementName =
name.substring(NON_PRIMITIVE_ARRAY_PREFIX.length(), name.length() - 1);
+ Class<?> elementClass = forName(elementName, classLoader);
+ return Array.newInstance(elementClass, 0).getClass();
+ }
+
+ // "[[I" or "[[Ljava.lang.String;" style arrays
+ if (name.startsWith(INTERNAL_ARRAY_PREFIX)) {
+ String elementName =
name.substring(INTERNAL_ARRAY_PREFIX.length());
+ Class<?> elementClass = forName(elementName, classLoader);
+ return Array.newInstance(elementClass, 0).getClass();
+ }
+
+ ClassLoader clToUse = classLoader;
+ if (clToUse == null) {
+ clToUse = getDefaultClassLoader();
+ }
+ try {
+ return (clToUse != null ? clToUse.loadClass(name) :
Class.forName(name));
+ } catch (ClassNotFoundException ex) {
+ int lastDotIndex = name.lastIndexOf(PACKAGE_SEPARATOR);
+ if (lastDotIndex != -1) {
+ String innerClassName =
+ name.substring(0, lastDotIndex) +
INNER_CLASS_SEPARATOR + name.substring(lastDotIndex + 1);
+ try {
+ return (clToUse != null ?
clToUse.loadClass(innerClassName) : Class.forName(innerClassName));
+ } catch (ClassNotFoundException ex2) {
+ // Swallow - let original exception get through
+ }
+ }
+ throw ex;
+ }
+ }
+
+
+ /**
+ * Resolve the given class name as primitive class, if appropriate,
+ * according to the JVM's naming rules for primitive classes.
+ * <p>Also supports the JVM's internal class names for primitive arrays.
+ * Does <i>not</i> support the "[]" suffix notation for primitive arrays;
+ * this is only supported by {@link #forName(String, ClassLoader)}.
+ *
+ * @param name the name current the potentially primitive class
+ * @return the primitive class, or {@code 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 = PRIMITIVE_TYPE_NAME_MAP.get(name);
+ }
+ return result;
+ }
+
+ /**
+ * Determine whether the {@link Class} identified by the supplied name is
present
+ * and can be loaded. Will return {@code false} if either the class or
+ * one current its dependencies is not present or cannot be loaded.
+ *
+ * @param className the name current the class to check
+ * @param classLoader the class loader to use
+ * (may be {@code 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 current its dependencies is not present...
+ return false;
+ }
+ }
+
+
+ /**
+ * 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 current
it.
+ *
+ * @param clazz the class to analyze
+ * @param classLoader the ClassLoader to potentially cache metadata in
+ */
+ public static boolean isCacheSafe(Class<?> clazz, ClassLoader classLoader)
{
+ Objects.requireNonNull(clazz, "Class must not be null");
+ try {
+ ClassLoader target = clazz.getClassLoader();
+ if (target == null) {
+ return true;
+ }
+ ClassLoader cur = classLoader;
+ if (cur == target) {
+ return true;
+ }
+ while (cur != null) {
+ cur = cur.getParent();
+ if (cur == target) {
+ return true;
+ }
+ }
+ return false;
+ } catch (SecurityException ex) {
+ // Probably from the system ClassLoader - let's consider it safe.
+ return true;
+ }
+ }
+
+
+ /**
+ * Return the qualified name current the given class: usually simply
+ * the class name, but component type class name + "[]" for arrays.
+ *
+ * @param clazz the class
+ * @return the qualified name current the class
+ */
+ public static String getQualifiedName(Class<?> clazz) {
+ Objects.requireNonNull(clazz, "Class must not be null");
+ if (clazz.isArray()) {
+ return getQualifiedNameForArray(clazz);
+ } else {
+ return clazz.getName();
+ }
+ }
+
+ /**
+ * 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) {
+ StringBuilder result = new StringBuilder();
+ while (clazz.isArray()) {
+ clazz = clazz.getComponentType();
+ result.append(ClassUtils.ARRAY_SUFFIX);
+ }
+ result.insert(0, clazz.getName());
+ return result.toString();
+ }
+
+ /**
+ * Return the qualified name current the given method, consisting current
+ * fully qualified interface/class name + "." + method name.
+ *
+ * @param method the method
+ * @return the qualified name current the method
+ */
+ public static String getQualifiedMethodName(Method method) {
+ Objects.requireNonNull(method, "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 current implemented interfaces for JDK proxies.
+ *
+ * @param keys the keys to introspect
+ * @return the qualified name current the class
+ */
+ public static String getDescriptiveType(Object keys) {
+ if (keys == null) {
+ return null;
+ }
+ Class<?> clazz = keys.getClass();
+ if (Proxy.isProxyClass(clazz)) {
+ StringBuilder result = new StringBuilder(clazz.getName());
+ result.append(" implementing ");
+ Class<?>[] ifcs = clazz.getInterfaces();
+ for (int i = 0; i < ifcs.length; i++) {
+ result.append(ifcs[i].getName());
+ if (i < ifcs.length - 1) {
+ result.append(',');
+ }
+ }
+ return result.toString();
+ } else if (clazz.isArray()) {
+ return getQualifiedNameForArray(clazz);
+ } else {
+ return clazz.getName();
+ }
+ }
+
+ /**
+ * Check whether the given class matches the user-specified type name.
+ *
+ * @param clazz the class to check
+ * @param typeName the type name to match
+ */
+ public static boolean matchesTypeName(Class<?> clazz, String typeName) {
+ return (typeName != null &&
+ (typeName.equals(clazz.getName()) ||
typeName.equals(clazz.getSimpleName()) ||
+ (clazz.isArray() &&
typeName.equals(getQualifiedNameForArray(clazz)))));
+ }
+
+
+ /**
+ * Determine whether the given class has a public constructor with the
given signature.
+ * <p>Essentially translates {@code NoSuchMethodException} to "false".
+ *
+ * @param clazz the clazz to analyze
+ * @param paramTypes the parameter types current the method
+ * @return whether the class has a corresponding constructor
+ * @see Class#getMethod
+ */
+ public static boolean hasConstructor(Class<?> clazz, Class<?>...
paramTypes) {
+ return (getConstructorIfAvailable(clazz, paramTypes) != null);
+ }
+
+ /**
+ * Determine whether the given class has a public constructor with the
given signature,
+ * and return it if available (else return {@code null}).
+ * <p>Essentially translates {@code NoSuchMethodException} to {@code null}.
+ *
+ * @param clazz the clazz to analyze
+ * @param paramTypes the parameter types current the method
+ * @return the constructor, or {@code null} if not found
+ * @see Class#getConstructor
+ */
+ public static <T> Constructor<T> getConstructorIfAvailable(Class<T> clazz,
Class<?>... paramTypes) {
+ Objects.requireNonNull(clazz, "Class must not be null");
+ try {
+ return clazz.getConstructor(paramTypes);
+ } catch (NoSuchMethodException ex) {
+ return null;
+ }
+ }
+
+ /**
+ * Determine whether the given class has a public method with the given
signature.
+ * <p>Essentially translates {@code NoSuchMethodException} to "false".
+ *
+ * @param clazz the clazz to analyze
+ * @param methodName the name current the method
+ * @param paramTypes the parameter types current the method
+ * @return whether the class has a corresponding method
+ * @see 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 public method with the given
signature,
+ * and return it if available (else throws an {@code
IllegalStateException}).
+ * <p>In case current any signature specified, only returns the method if
there is a
+ * unique candidate, i.e. a single public method with the specified name.
+ * <p>Essentially translates {@code NoSuchMethodException} to {@code
IllegalStateException}.
+ *
+ * @param clazz the clazz to analyze
+ * @param methodName the name current the method
+ * @param paramTypes the parameter types current the method
+ * (may be {@code null} to indicate any signature)
+ * @return the method (never {@code null})
+ * @throws IllegalStateException if the method has not been found
+ * @see Class#getMethod
+ */
+ public static Method getMethod(Class<?> clazz, String methodName,
Class<?>... paramTypes) {
+ Objects.requireNonNull(clazz, "Class must not be null");
+ Objects.requireNonNull(methodName, "Method name must not be null");
+ if (paramTypes != null) {
+ try {
+ return clazz.getMethod(methodName, paramTypes);
+ } catch (NoSuchMethodException ex) {
+ throw new IllegalStateException("Expected method not found: "
+ ex);
+ }
+ } else {
+ Set<Method> candidates = new HashSet<Method>(1);
+ Method[] methods = clazz.getMethods();
+ for (Method method : methods) {
+ if (methodName.equals(method.getName())) {
+ candidates.add(method);
+ }
+ }
+ if (candidates.size() == 1) {
+ return candidates.iterator().next();
+ } else if (candidates.isEmpty()) {
+ throw new IllegalStateException("Expected method not found: "
+ clazz + "." + methodName);
+ } else {
+ throw new IllegalStateException("No unique method found: " +
clazz + "." + methodName);
+ }
+ }
+ }
+
+ /**
+ * Determine whether the given class has a public method with the given
signature,
+ * and return it if available (else return {@code null}).
+ * <p>In case current any signature specified, only returns the method if
there is a
+ * unique candidate, i.e. a single public method with the specified name.
+ * <p>Essentially translates {@code NoSuchMethodException} to {@code null}.
+ *
+ * @param clazz the clazz to analyze
+ * @param methodName the name current the method
+ * @param paramTypes the parameter types current the method
+ * (may be {@code null} to indicate any signature)
+ * @return the method, or {@code null} if not found
+ * @see Class#getMethod
+ */
+ public static Method getMethodIfAvailable(Class<?> clazz, String
methodName, Class<?>... paramTypes) {
+ Objects.requireNonNull(clazz, "Class must not be null");
+ Objects.requireNonNull(methodName, "Method name must not be null");
+ if (paramTypes != null) {
+ try {
+ return clazz.getMethod(methodName, paramTypes);
+ } catch (NoSuchMethodException ex) {
+ return null;
+ }
+ } else {
+ Set<Method> candidates = new HashSet<Method>(1);
+ Method[] methods = clazz.getMethods();
+ for (Method method : methods) {
+ if (methodName.equals(method.getName())) {
+ candidates.add(method);
+ }
+ }
+ if (candidates.size() == 1) {
+ return candidates.iterator().next();
+ }
+ return null;
+ }
+ }
+
+ /**
+ * Return the number current 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 current the method
+ * @return the number current methods with the given name
+ */
+ public static int getMethodCountForName(Class<?> clazz, String methodName)
{
+ Objects.requireNonNull(clazz, "Class must not be null");
+ Objects.requireNonNull(methodName, "Method name must not be null");
+ int count = 0;
+ Method[] declaredMethods = clazz.getDeclaredMethods();
+ for (Method method : declaredMethods) {
+ if (methodName.equals(method.getName())) {
+ count++;
+ }
+ }
+ Class<?>[] ifcs = clazz.getInterfaces();
+ for (Class<?> ifc : ifcs) {
+ count += getMethodCountForName(ifc, methodName);
+ }
+ if (clazz.getSuperclass() != null) {
+ count += getMethodCountForName(clazz.getSuperclass(), methodName);
+ }
+ return count;
+ }
+
+ /**
+ * Does the given class or one current its superclasses at least have one
or more
+ * methods with the supplied name (with any argument types)?
+ * Includes non-public methods.
+ *
+ * @param clazz the clazz to check
+ * @param methodName the name current the method
+ * @return whether there is at least one method with the given name
+ */
+ public static boolean hasAtLeastOneMethodWithName(Class<?> clazz, String
methodName) {
+ Objects.requireNonNull(clazz, "Class must not be null");
+ Objects.requireNonNull(methodName, "Method name must not be null");
+ Method[] declaredMethods = clazz.getDeclaredMethods();
+ for (Method method : declaredMethods) {
+ if (method.getName().equals(methodName)) {
+ return true;
+ }
+ }
+ Class<?>[] ifcs = clazz.getInterfaces();
+ for (Class<?> ifc : ifcs) {
+ if (hasAtLeastOneMethodWithName(ifc, 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 {@code IFoo.bar()} and the
+ * target class may be {@code DefaultFoo}. In this case, the method may be
+ * {@code DefaultFoo.bar()}. This enables attributes on that method to be
found.
+ * <p><b>NOTE:</b> In contrast to {@code
org.springframework.aop.support.AopUtils#getMostSpecificMethod},
+ * this method does <i>not</i> resolve Java 5 bridge methods automatically.
+ * Call {@code
org.springframework.core.BridgeMethodResolver#findBridgedMethod}
+ * if bridge method resolution is desirable (e.g. for obtaining metadata
from
+ * the original method definition).
+ * <p><b>NOTE:</b> Since Spring 3.1.1, if Java security settings disallow
reflective
+ * access (e.g. calls to {@code Class#getDeclaredMethods} etc, this
implementation
+ * will fall back to returning the originally provided method.
+ *
+ * @param method the method to be invoked, which may come from an
interface
+ * @param targetClass the target class for the current invocation.
+ * May be {@code null} or may not even implement the
method.
+ * @return the specific target method, or the original method if the
+ * {@code targetClass} doesn't implement it or is {@code null}
+ */
+ public static Method getMostSpecificMethod(Method method, Class<?>
targetClass) {
+ if (method != null && isOverridable(method, targetClass) &&
+ targetClass != null &&
!targetClass.equals(method.getDeclaringClass())) {
+ try {
+ if (Modifier.isPublic(method.getModifiers())) {
+ try {
+ return targetClass.getMethod(method.getName(),
method.getParameterTypes());
+ } catch (NoSuchMethodException ex) {
+ return method;
+ }
+ } else {
+ Method specificMethod =
+ ReflectionUtils.findMethod(targetClass,
method.getName(), method.getParameterTypes());
+ return (specificMethod != null ? specificMethod : method);
+ }
+ } catch (SecurityException ex) {
+ // Security settings are disallowing reflective access; fall
back to 'method' below.
+ }
+ }
+ return method;
+ }
+
+ /**
+ * Determine whether the given method is declared by the user or at least
pointing to
+ * a user-declared method.
+ * <p>Checks {@link Method#isSynthetic()} (for implementation methods) as
well as the
+ * {@code GroovyObject} interface (for interface methods; on an
implementation class,
+ * implementations current the {@code GroovyObject} methods will be marked
as synthetic anyway).
+ * Note that, despite being synthetic, bridge methods ({@link
Method#isBridge()}) are considered
+ * as user-level methods since they are eventually pointing to a
user-declared generic method.
+ *
+ * @param method the method to check
+ * @return {@code true} if the method can be considered as user-declared;
[@code false} otherwise
+ */
+ public static boolean isUserLevelMethod(Method method) {
+ Objects.requireNonNull(method, "Method must not be null");
+ return (method.isBridge() || (!method.isSynthetic() &&
!isGroovyObjectMethod(method)));
+ }
+
+ private static boolean isGroovyObjectMethod(Method method) {
+ return
method.getDeclaringClass().getName().equals("groovy.lang.GroovyObject");
+ }
+
+ /**
+ * Determine whether the given method is overridable in the given target
class.
+ *
+ * @param method the method to check
+ * @param targetClass the target class to check against
+ */
+ private static boolean isOverridable(Method method, Class<?> targetClass) {
+ if (Modifier.isPrivate(method.getModifiers())) {
+ return false;
+ }
+ if (Modifier.isPublic(method.getModifiers()) ||
Modifier.isProtected(method.getModifiers())) {
+ return true;
+ }
+ return
getPackageName(method.getDeclaringClass()).equals(getPackageName(targetClass));
+ }
+
+
+ /**
+ * Determine the name current the package current the given class,
+ * e.g. "java.lang" for the {@code 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) {
+ Objects.requireNonNull(clazz, "Class must not be null");
+ return getPackageName(clazz.getName());
+ }
+
+ /**
+ * Determine the name current the package current the given
fully-qualified class name,
+ * e.g. "java.lang" for the {@code java.lang.String} class name.
+ *
+ * @param fqClassName the fully-qualified class name
+ * @return the package name, or the empty String if the class
+ * is defined in the dObjects.requireNonNullefault package
+ */
+ public static String getPackageName(String fqClassName) {
+ Objects.requireNonNull(fqClassName, "Class name must not be null");
+ int lastDotIndex = fqClassName.lastIndexOf(PACKAGE_SEPARATOR);
+ return (lastDotIndex != -1 ? fqClassName.substring(0, lastDotIndex) :
"");
+ }
+
+ /**
+ * Return a public static method current 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 {@code 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) {
+ Objects.requireNonNull(clazz, "Class must not be null");
+ Objects.requireNonNull(methodName, "Method name must not be null");
+ try {
+ Method method = clazz.getMethod(methodName, args);
+ return Modifier.isStatic(method.getModifiers()) ? method : null;
+ } 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) {
+ Objects.requireNonNull(clazz, "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) {
+ Objects.requireNonNull(clazz, "Class must not be null");
+ return (clazz.isPrimitive() || isPrimitiveWrapper(clazz));
+ }
+
+ /**
+ * Check if the given class represents an array current 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) {
+ Objects.requireNonNull(clazz, "Class must not be null");
+ return (clazz.isArray() && clazz.getComponentType().isPrimitive());
+ }
+
+ /**
+ * Check if the given class represents an array current 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) {
+ Objects.requireNonNull(clazz, "Class must not be null");
+ return (clazz.isArray() &&
isPrimitiveWrapper(clazz.getComponentType()));
+ }
+
+ /**
+ * Resolve the given class if it is a primitive class,
+ * returning the corresponding primitive wrapper type instead.
+ *
+ * @param clazz the class to check
+ * @return the original class, or a primitive wrapper for the original
primitive type
+ */
+ public static Class<?> resolvePrimitiveIfNecessary(Class<?> clazz) {
Objects.requireNonNull(clazz, "Class must not be null");
- try {
- ClassLoader target = clazz.getClassLoader();
- if (target == null) {
- return true;
- }
- ClassLoader cur = classLoader;
- if (cur == target) {
- return true;
- }
- while (cur != null) {
- cur = cur.getParent();
- if (cur == target) {
- return true;
- }
- }
- return false;
- }
- catch (SecurityException ex) {
- // Probably from the system ClassLoader - let's
consider it safe.
- return true;
- }
- }
-
-
- /**
- * Return the qualified name current the given class: usually simply
- * the class name, but component type class name + "[]" for arrays.
- * @param clazz the class
- * @return the qualified name current the class
- */
- public static String getQualifiedName(Class<?> clazz) {
- Objects.requireNonNull(clazz, "Class must not be null");
- if (clazz.isArray()) {
- return getQualifiedNameForArray(clazz);
- }
- else {
- return clazz.getName();
- }
- }
-
- /**
- * 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) {
- StringBuilder result = new StringBuilder();
- while (clazz.isArray()) {
- clazz = clazz.getComponentType();
- result.append(ClassUtils.ARRAY_SUFFIX);
- }
- result.insert(0, clazz.getName());
- return result.toString();
- }
-
- /**
- * Return the qualified name current the given method, consisting
current
- * fully qualified interface/class name + "." + method name.
- * @param method the method
- * @return the qualified name current the method
- */
- public static String getQualifiedMethodName(Method method) {
- Objects.requireNonNull(method, "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 current implemented interfaces for JDK proxies.
- * @param keys the keys to introspect
- * @return the qualified name current the class
- */
- public static String getDescriptiveType(Object keys) {
- if (keys == null) {
- return null;
- }
- Class<?> clazz = keys.getClass();
- if (Proxy.isProxyClass(clazz)) {
- StringBuilder result = new
StringBuilder(clazz.getName());
- result.append(" implementing ");
- Class<?>[] ifcs = clazz.getInterfaces();
- for (int i = 0; i < ifcs.length; i++) {
- result.append(ifcs[i].getName());
- if (i < ifcs.length - 1) {
- result.append(',');
- }
- }
- return result.toString();
- }
- else if (clazz.isArray()) {
- return getQualifiedNameForArray(clazz);
- }
- else {
- return clazz.getName();
- }
- }
-
- /**
- * Check whether the given class matches the user-specified type name.
- * @param clazz the class to check
- * @param typeName the type name to match
- */
- public static boolean matchesTypeName(Class<?> clazz, String typeName) {
- return (typeName != null &&
- (typeName.equals(clazz.getName()) ||
typeName.equals(clazz.getSimpleName()) ||
- (clazz.isArray() &&
typeName.equals(getQualifiedNameForArray(clazz)))));
- }
-
-
- /**
- * Determine whether the given class has a public constructor with the
given signature.
- * <p>Essentially translates {@code NoSuchMethodException} to "false".
- * @param clazz the clazz to analyze
- * @param paramTypes the parameter types current the method
- * @return whether the class has a corresponding constructor
- * @see Class#getMethod
- */
- public static boolean hasConstructor(Class<?> clazz, Class<?>...
paramTypes) {
- return (getConstructorIfAvailable(clazz, paramTypes) != null);
- }
-
- /**
- * Determine whether the given class has a public constructor with the
given signature,
- * and return it if available (else return {@code null}).
- * <p>Essentially translates {@code NoSuchMethodException} to {@code
null}.
- * @param clazz the clazz to analyze
- * @param paramTypes the parameter types current the method
- * @return the constructor, or {@code null} if not found
- * @see Class#getConstructor
- */
- public static <T> Constructor<T> getConstructorIfAvailable(Class<T>
clazz, Class<?>... paramTypes) {
- Objects.requireNonNull(clazz, "Class must not be null");
- try {
- return clazz.getConstructor(paramTypes);
- }
- catch (NoSuchMethodException ex) {
- return null;
- }
- }
-
- /**
- * Determine whether the given class has a public method with the given
signature.
- * <p>Essentially translates {@code NoSuchMethodException} to "false".
- * @param clazz the clazz to analyze
- * @param methodName the name current the method
- * @param paramTypes the parameter types current the method
- * @return whether the class has a corresponding method
- * @see 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 public method with the given
signature,
- * and return it if available (else throws an {@code
IllegalStateException}).
- * <p>In case current any signature specified, only returns the method
if there is a
- * unique candidate, i.e. a single public method with the specified
name.
- * <p>Essentially translates {@code NoSuchMethodException} to {@code
IllegalStateException}.
- * @param clazz the clazz to analyze
- * @param methodName the name current the method
- * @param paramTypes the parameter types current the method
- * (may be {@code null} to indicate any signature)
- * @return the method (never {@code null})
- * @throws IllegalStateException if the method has not been found
- * @see Class#getMethod
- */
- public static Method getMethod(Class<?> clazz, String methodName,
Class<?>... paramTypes) {
- Objects.requireNonNull(clazz, "Class must not be null");
- Objects.requireNonNull(methodName, "Method name must not be
null");
- if (paramTypes != null) {
- try {
- return clazz.getMethod(methodName, paramTypes);
- }
- catch (NoSuchMethodException ex) {
- throw new IllegalStateException("Expected
method not found: " + ex);
- }
- }
- else {
- Set<Method> candidates = new HashSet<Method>(1);
- Method[] methods = clazz.getMethods();
- for (Method method : methods) {
- if (methodName.equals(method.getName())) {
- candidates.add(method);
- }
- }
- if (candidates.size() == 1) {
- return candidates.iterator().next();
- }
- else if (candidates.isEmpty()) {
- throw new IllegalStateException("Expected
method not found: " + clazz + "." + methodName);
- }
- else {
- throw new IllegalStateException("No unique
method found: " + clazz + "." + methodName);
- }
- }
- }
-
- /**
- * Determine whether the given class has a public method with the given
signature,
- * and return it if available (else return {@code null}).
- * <p>In case current any signature specified, only returns the method
if there is a
- * unique candidate, i.e. a single public method with the specified
name.
- * <p>Essentially translates {@code NoSuchMethodException} to {@code
null}.
- * @param clazz the clazz to analyze
- * @param methodName the name current the method
- * @param paramTypes the parameter types current the method
- * (may be {@code null} to indicate any signature)
- * @return the method, or {@code null} if not found
- * @see Class#getMethod
- */
- public static Method getMethodIfAvailable(Class<?> clazz, String
methodName, Class<?>... paramTypes) {
- Objects.requireNonNull(clazz, "Class must not be null");
- Objects.requireNonNull(methodName, "Method name must not be
null");
- if (paramTypes != null) {
- try {
- return clazz.getMethod(methodName, paramTypes);
- }
- catch (NoSuchMethodException ex) {
- return null;
- }
- }
- else {
- Set<Method> candidates = new HashSet<Method>(1);
- Method[] methods = clazz.getMethods();
- for (Method method : methods) {
- if (methodName.equals(method.getName())) {
- candidates.add(method);
- }
- }
- if (candidates.size() == 1) {
- return candidates.iterator().next();
- }
- return null;
- }
- }
-
- /**
- * Return the number current 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 current the method
- * @return the number current methods with the given name
- */
- public static int getMethodCountForName(Class<?> clazz, String
methodName) {
- Objects.requireNonNull(clazz, "Class must not be null");
- Objects.requireNonNull(methodName, "Method name must not be
null");
- int count = 0;
- Method[] declaredMethods = clazz.getDeclaredMethods();
- for (Method method : declaredMethods) {
- if (methodName.equals(method.getName())) {
- count++;
- }
- }
- Class<?>[] ifcs = clazz.getInterfaces();
- for (Class<?> ifc : ifcs) {
- count += getMethodCountForName(ifc, methodName);
- }
- if (clazz.getSuperclass() != null) {
- count += getMethodCountForName(clazz.getSuperclass(),
methodName);
- }
- return count;
- }
-
- /**
- * Does the given class or one current its superclasses at least have
one or more
- * methods with the supplied name (with any argument types)?
- * Includes non-public methods.
- * @param clazz the clazz to check
- * @param methodName the name current the method
- * @return whether there is at least one method with the given name
- */
- public static boolean hasAtLeastOneMethodWithName(Class<?> clazz,
String methodName) {
- Objects.requireNonNull(clazz, "Class must not be null");
- Objects.requireNonNull(methodName, "Method name must not be
null");
- Method[] declaredMethods = clazz.getDeclaredMethods();
- for (Method method : declaredMethods) {
- if (method.getName().equals(methodName)) {
- return true;
- }
- }
- Class<?>[] ifcs = clazz.getInterfaces();
- for (Class<?> ifc : ifcs) {
- if (hasAtLeastOneMethodWithName(ifc, 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 {@code IFoo.bar()} and the
- * target class may be {@code DefaultFoo}. In this case, the method may
be
- * {@code DefaultFoo.bar()}. This enables attributes on that method to
be found.
- * <p><b>NOTE:</b> In contrast to {@code
org.springframework.aop.support.AopUtils#getMostSpecificMethod},
- * this method does <i>not</i> resolve Java 5 bridge methods
automatically.
- * Call {@code
org.springframework.core.BridgeMethodResolver#findBridgedMethod}
- * if bridge method resolution is desirable (e.g. for obtaining
metadata from
- * the original method definition).
- * <p><b>NOTE:</b> Since Spring 3.1.1, if Java security settings
disallow reflective
- * access (e.g. calls to {@code Class#getDeclaredMethods} etc, this
implementation
- * will fall back to returning the originally provided method.
- * @param method the method to be invoked, which may come from an
interface
- * @param targetClass the target class for the current invocation.
- * May be {@code null} or may not even implement the method.
- * @return the specific target method, or the original method if the
- * {@code targetClass} doesn't implement it or is {@code null}
- */
- public static Method getMostSpecificMethod(Method method, Class<?>
targetClass) {
- if (method != null && isOverridable(method, targetClass) &&
- targetClass != null &&
!targetClass.equals(method.getDeclaringClass())) {
- try {
- if (Modifier.isPublic(method.getModifiers())) {
- try {
- return
targetClass.getMethod(method.getName(), method.getParameterTypes());
- }
- catch (NoSuchMethodException ex) {
- return method;
- }
- }
- else {
- Method specificMethod =
-
ReflectionUtils.findMethod(targetClass, method.getName(),
method.getParameterTypes());
- return (specificMethod != null ?
specificMethod : method);
- }
- }
- catch (SecurityException ex) {
- // Security settings are disallowing reflective
access; fall back to 'method' below.
- }
- }
- return method;
- }
-
- /**
- * Determine whether the given method is declared by the user or at
least pointing to
- * a user-declared method.
- * <p>Checks {@link Method#isSynthetic()} (for implementation methods)
as well as the
- * {@code GroovyObject} interface (for interface methods; on an
implementation class,
- * implementations current the {@code GroovyObject} methods will be
marked as synthetic anyway).
- * Note that, despite being synthetic, bridge methods ({@link
Method#isBridge()}) are considered
- * as user-level methods since they are eventually pointing to a
user-declared generic method.
- * @param method the method to check
- * @return {@code true} if the method can be considered as
user-declared; [@code false} otherwise
- */
- public static boolean isUserLevelMethod(Method method) {
- Objects.requireNonNull(method, "Method must not be null");
- return (method.isBridge() || (!method.isSynthetic() &&
!isGroovyObjectMethod(method)));
- }
-
- private static boolean isGroovyObjectMethod(Method method) {
- return
method.getDeclaringClass().getName().equals("groovy.lang.GroovyObject");
- }
-
- /**
- * Determine whether the given method is overridable in the given
target class.
- * @param method the method to check
- * @param targetClass the target class to check against
- */
- private static boolean isOverridable(Method method, Class<?>
targetClass) {
- if (Modifier.isPrivate(method.getModifiers())) {
- return false;
- }
- if (Modifier.isPublic(method.getModifiers()) ||
Modifier.isProtected(method.getModifiers())) {
- return true;
- }
- return
getPackageName(method.getDeclaringClass()).equals(getPackageName(targetClass));
- }
-
-
- /**
- * Determine the name current the package current the given class,
- * e.g. "java.lang" for the {@code 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) {
+ return (clazz.isPrimitive() && clazz != void.class ?
PRIMITIVE_TYPE_TO_WRAPPER_MAP.get(clazz) : clazz);
+ }
+
+ /**
+ * 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 keys type that should be assigned to the target type
+ * @return if the target type is assignable from the keys type
+ */
+ public static boolean isAssignable(Class<?> lhsType, Class<?> rhsType) {
+ Objects.requireNonNull(lhsType, "Left-hand side type must not be
null");
+ Objects.requireNonNull(rhsType, "Right-hand side type must not be
null");
+ if (lhsType.isAssignableFrom(rhsType)) {
+ return true;
+ }
+ if (lhsType.isPrimitive()) {
+ Class<?> resolvedPrimitive =
PRIMITIVE_WRAPPER_TYPE_MAP.get(rhsType);
+ if (resolvedPrimitive != null &&
lhsType.equals(resolvedPrimitive)) {
+ return true;
+ }
+ } else {
+ Class<?> resolvedWrapper =
PRIMITIVE_TYPE_TO_WRAPPER_MAP.get(rhsType);
+ if (resolvedWrapper != null &&
lhsType.isAssignableFrom(resolvedWrapper)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Determine if the given type is assignable from the given keys,
+ * assuming setting by reflection. Considers primitive wrapper classes
+ * as assignable to the corresponding primitive types.
+ *
+ * @param type the target type
+ * @param keys the keys that should be assigned to the type
+ * @return if the type is assignable from the keys
+ */
+ public static boolean isAssignableValue(Class<?> type, Object keys) {
+ Objects.requireNonNull(type, "Type must not be null");
+ return (keys != null ? isAssignable(type, keys.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) {
+ Objects.requireNonNull(resourcePath, "Resource path must not be null");
+ return resourcePath.replace(PATH_SEPARATOR, PACKAGE_SEPARATOR);
+ }
+
+ /**
+ * 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) {
+ Objects.requireNonNull(className, "Class name must not be null");
+ return className.replace(PACKAGE_SEPARATOR, PATH_SEPARATOR);
+ }
+
+ /**
+ * Return a path suitable for use with {@code ClassLoader.getResource}
+ * (also suitable for use with {@code Class.getResource} by prepending a
+ * slash ('/') to the return keys). Built by taking the package current
the specified
+ * class file, converting all dots ('.') to slashes ('/'), adding a
trailing slash
+ * if necessary, and concatenating the specified resource name to this.
+ * <br/>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 {@code 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 ClassLoader#getResource
+ * @see Class#getResource
+ */
+ public static String addResourcePathToPackagePath(Class<?> clazz, String
resourceName) {
+ Objects.requireNonNull(resourceName, "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 current 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 current a resource and
fed
+ * directly to {@code ClassLoader.getResource()}. For it to be fed to
+ * {@code Class.getResource} instead, a leading slash would also have
+ * to be prepended to the returned keys.
+ *
+ * @param clazz the input class. A {@code null} keys 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(PACKAGE_SEPARATOR);
+ if (packageEndIndex == -1) {
+ return "";
+ }
+ String packageName = className.substring(0, packageEndIndex);
+ return packageName.replace(PACKAGE_SEPARATOR, PATH_SEPARATOR);
+ }
+
+ /**
+ * Build a String that consists current the names current the
classes/interfaces
+ * in the given array.
+ * <p>Basically like {@code AbstractCollection.toString()}, but stripping
+ * the "class "/"interface " prefix before every class name.
+ *
+ * @param classes a Collection current Class objects (may be {@code null})
+ * @return a String current 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 current the names current the
classes/interfaces
+ * in the given collection.
+ * <p>Basically like {@code AbstractCollection.toString()}, but stripping
+ * the "class "/"interface " prefix before every class name.
+ *
+ * @param classes a Collection current Class objects (may be {@code null})
+ * @return a String current form "[com.foo.Bar, com.foo.Baz]"
+ * @see java.util.AbstractCollection#toString()
+ */
+ public static String classNamesToString(Collection<Class<?>> classes) {
+ if (classes.isEmpty()) {
+ return "[]";
+ }
+ StringBuilder sb = new StringBuilder("[");
+ for (Iterator<Class<?>> it = classes.iterator(); it.hasNext(); ) {
+ Class<?> clazz = it.next();
+ sb.append(clazz.getName());
+ if (it.hasNext()) {
+ sb.append(", ");
+ }
+ }
+ sb.append("]");
+ return sb.toString();
+ }
+
+ /**
+ * Copy the given Collection into a Class array.
+ * The Collection must contain Class elements only.
+ *
+ * @param collection the Collection to copy
+ * @return the Class array ({@code null} if the passed-in
+ * Collection was {@code null})
+ */
+ public static Class<?>[] toClassArray(Collection<Class<?>> collection) {
+ if (collection == null) {
+ return null;
+ }
+ return collection.toArray(new Class<?>[collection.size()]);
+ }
+
+ /**
+ * Return all interfaces that the given instance implements as array,
+ * including ones implemented by superclasses.
+ *
+ * @param instance the instance to analyze for interfaces
+ * @return all interfaces that the given instance implements as array
+ */
+ public static Class<?>[] getAllInterfaces(Object instance) {
+ Objects.requireNonNull(instance, "Instance must not be null");
+ return getAllInterfacesForClass(instance.getClass());
+ }
+
+ /**
+ * Return all interfaces that the given class implements as array,
+ * including ones implemented by superclasses.
+ * <p>If the class itself is an interface, it gets returned as sole
interface.
+ *
+ * @param clazz the class to analyze 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.
+ * <p>If the class itself is an interface, it gets returned as sole
interface.
+ *
+ * @param clazz the class to analyze for interfaces
+ * @param classLoader the ClassLoader that the interfaces need to be
visible in
+ * (may be {@code null} when accepting all declared
interfaces)
+ * @return all interfaces that the given object implements as array
+ */
+ public static Class<?>[] getAllInterfacesForClass(Class<?> clazz,
ClassLoader classLoader) {
+ Set<Class<?>> ifcs = getAllInterfacesForClassAsSet(clazz, classLoader);
+ return ifcs.toArray(new Class<?>[ifcs.size()]);
+ }
+
+ /**
+ * Return all interfaces that the given instance implements as Set,
+ * including ones implemented by superclasses.
+ *
+ * @param instance the instance to analyze for interfaces
+ * @return all interfaces that the given instance implements as Set
+ */
+ public static Set<Class<?>> getAllInterfacesAsSet(Object instance) {
+ Objects.requireNonNull(instance, "Instance must not be null");
+ return getAllInterfacesForClassAsSet(instance.getClass());
+ }
+
+ /**
+ * Return all interfaces that the given class implements as Set,
+ * including ones implemented by superclasses.
+ * <p>If the class itself is an interface, it gets returned as sole
interface.
+ *
+ * @param clazz the class to analyze for interfaces
+ * @return all interfaces that the given object implements as Set
+ */
+ public static Set<Class<?>> getAllInterfacesForClassAsSet(Class<?> clazz) {
+ return getAllInterfacesForClassAsSet(clazz, null);
+ }
+
+ /**
+ * Return all interfaces that the given class implements as Set,
+ * including ones implemented by superclasses.
+ * <p>If the class itself is an interface, it gets returned as sole
interface.
+ *
+ * @param clazz the class to analyze for interfaces
+ * @param classLoader the ClassLoader that the interfaces need to be
visible in
+ * (may be {@code null} when accepting all declared
interfaces)
+ * @return all interfaces that the given object implements as Set
+ */
+ public static Set<Class<?>> getAllInterfacesForClassAsSet(Class<?> clazz,
ClassLoader classLoader) {
Objects.requireNonNull(clazz, "Class must not be null");
- return getPackageName(clazz.getName());
- }
-
- /**
- * Determine the name current the package current the given
fully-qualified class name,
- * e.g. "java.lang" for the {@code java.lang.String} class name.
- * @param fqClassName the fully-qualified class name
- * @return the package name, or the empty String if the class
- * is defined in the dObjects.requireNonNullefault package
- */
- public static String getPackageName(String fqClassName) {
- Objects.requireNonNull(fqClassName, "Class name must not be
null");
- int lastDotIndex = fqClassName.lastIndexOf(PACKAGE_SEPARATOR);
- return (lastDotIndex != -1 ? fqClassName.substring(0,
lastDotIndex) : "");
- }
-
- /**
- * Return a public static method current 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 {@code 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) {
- Objects.requireNonNull(clazz, "Class must not be null");
- Objects.requireNonNull(methodName, "Method name must not be
null");
- try {
- Method method = clazz.getMethod(methodName, args);
- return Modifier.isStatic(method.getModifiers()) ?
method : null;
- }
- 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) {
- Objects.requireNonNull(clazz, "Class must not be null");
- return primitiveWrapperTypeMap.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) {
- Objects.requireNonNull(clazz, "Class must not be null");
- return (clazz.isPrimitive() || isPrimitiveWrapper(clazz));
- }
-
- /**
- * Check if the given class represents an array current 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) {
- Objects.requireNonNull(clazz, "Class must not be null");
- return (clazz.isArray() &&
clazz.getComponentType().isPrimitive());
- }
-
- /**
- * Check if the given class represents an array current 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) {
- Objects.requireNonNull(clazz, "Class must not be null");
- return (clazz.isArray() &&
isPrimitiveWrapper(clazz.getComponentType()));
- }
-
- /**
- * Resolve the given class if it is a primitive class,
- * returning the corresponding primitive wrapper type instead.
- * @param clazz the class to check
- * @return the original class, or a primitive wrapper for the original
primitive type
- */
- public static Class<?> resolvePrimitiveIfNecessary(Class<?> clazz) {
- Objects.requireNonNull(clazz, "Class must not be null");
- return (clazz.isPrimitive() && clazz != void.class?
primitiveTypeToWrapperMap.get(clazz) : clazz);
- }
-
- /**
- * 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 keys type that should be assigned to the target
type
- * @return if the target type is assignable from the keys type
- */
- public static boolean isAssignable(Class<?> lhsType, Class<?> rhsType) {
- Objects.requireNonNull(lhsType, "Left-hand side type must not
be null");
- Objects.requireNonNull(rhsType, "Right-hand side type must not
be null");
- if (lhsType.isAssignableFrom(rhsType)) {
- return true;
- }
- if (lhsType.isPrimitive()) {
- Class<?> resolvedPrimitive =
primitiveWrapperTypeMap.get(rhsType);
- if (resolvedPrimitive != null &&
lhsType.equals(resolvedPrimitive)) {
- return true;
- }
- }
- else {
- Class<?> resolvedWrapper =
primitiveTypeToWrapperMap.get(rhsType);
- if (resolvedWrapper != null &&
lhsType.isAssignableFrom(resolvedWrapper)) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * Determine if the given type is assignable from the given keys,
- * assuming setting by reflection. Considers primitive wrapper classes
- * as assignable to the corresponding primitive types.
- * @param type the target type
- * @param keys the keys that should be assigned to the type
- * @return if the type is assignable from the keys
- */
- public static boolean isAssignableValue(Class<?> type, Object keys) {
- Objects.requireNonNull(type, "Type must not be null");
- return (keys != null ? isAssignable(type, keys.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) {
- Objects.requireNonNull(resourcePath, "Resource path must not be
null");
- return resourcePath.replace(PATH_SEPARATOR, PACKAGE_SEPARATOR);
- }
-
- /**
- * 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) {
- Objects.requireNonNull(className, "Class name must not be
null");
- return className.replace(PACKAGE_SEPARATOR, PATH_SEPARATOR);
- }
-
- /**
- * Return a path suitable for use with {@code ClassLoader.getResource}
- * (also suitable for use with {@code Class.getResource} by prepending a
- * slash ('/') to the return keys). Built by taking the package current
the specified
- * class file, converting all dots ('.') to slashes ('/'), adding a
trailing slash
- * if necessary, and concatenating the specified resource name to this.
- * <br/>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 {@code 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 ClassLoader#getResource
- * @see Class#getResource
- */
- public static String addResourcePathToPackagePath(Class<?> clazz,
String resourceName) {
- Objects.requireNonNull(resourceName, "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 current
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 current a resource
and fed
- * directly to {@code ClassLoader.getResource()}. For it to be fed to
- * {@code Class.getResource} instead, a leading slash would also have
- * to be prepended to the returned keys.
- * @param clazz the input class. A {@code null} keys 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(PACKAGE_SEPARATOR);
- if (packageEndIndex == -1) {
- return "";
- }
- String packageName = className.substring(0, packageEndIndex);
- return packageName.replace(PACKAGE_SEPARATOR, PATH_SEPARATOR);
- }
-
- /**
- * Build a String that consists current the names current the
classes/interfaces
- * in the given array.
- * <p>Basically like {@code AbstractCollection.toString()}, but
stripping
- * the "class "/"interface " prefix before every class name.
- * @param classes a Collection current Class objects (may be {@code
null})
- * @return a String current 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 current the names current the
classes/interfaces
- * in the given collection.
- * <p>Basically like {@code AbstractCollection.toString()}, but
stripping
- * the "class "/"interface " prefix before every class name.
- * @param classes a Collection current Class objects (may be {@code
null})
- * @return a String current form "[com.foo.Bar, com.foo.Baz]"
- * @see java.util.AbstractCollection#toString()
- */
- public static String classNamesToString(Collection<Class<?>> classes) {
- if (classes.isEmpty()) {
- return "[]";
- }
- StringBuilder sb = new StringBuilder("[");
- for (Iterator<Class<?>> it = classes.iterator(); it.hasNext();
) {
- Class<?> clazz = it.next();
- sb.append(clazz.getName());
- if (it.hasNext()) {
- sb.append(", ");
- }
- }
- sb.append("]");
- return sb.toString();
- }
-
- /**
- * Copy the given Collection into a Class array.
- * The Collection must contain Class elements only.
- * @param collection the Collection to copy
- * @return the Class array ({@code null} if the passed-in
- * Collection was {@code null})
- */
- public static Class<?>[] toClassArray(Collection<Class<?>> collection) {
- if (collection == null) {
- return null;
- }
- return collection.toArray(new Class<?>[collection.size()]);
- }
-
- /**
- * Return all interfaces that the given instance implements as array,
- * including ones implemented by superclasses.
- * @param instance the instance to analyze for interfaces
- * @return all interfaces that the given instance implements as array
- */
- public static Class<?>[] getAllInterfaces(Object instance) {
- Objects.requireNonNull(instance, "Instance must not be null");
- return getAllInterfacesForClass(instance.getClass());
- }
-
- /**
- * Return all interfaces that the given class implements as array,
- * including ones implemented by superclasses.
- * <p>If the class itself is an interface, it gets returned as sole
interface.
- * @param clazz the class to analyze 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.
- * <p>If the class itself is an interface, it gets returned as sole
interface.
- * @param clazz the class to analyze for interfaces
- * @param classLoader the ClassLoader that the interfaces need to be
visible in
- * (may be {@code null} when accepting all declared interfaces)
- * @return all interfaces that the given object implements as array
- */
- public static Class<?>[] getAllInterfacesForClass(Class<?> clazz,
ClassLoader classLoader) {
- Set<Class<?>> ifcs = getAllInterfacesForClassAsSet(clazz,
classLoader);
- return ifcs.toArray(new Class<?>[ifcs.size()]);
- }
-
- /**
- * Return all interfaces that the given instance implements as Set,
- * including ones implemented by superclasses.
- * @param instance the instance to analyze for interfaces
- * @return all interfaces that the given instance implements as Set
- */
- public static Set<Class<?>> getAllInterfacesAsSet(Object instance) {
- Objects.requireNonNull(instance, "Instance must not be null");
- return getAllInterfacesForClassAsSet(instance.getClass());
- }
-
- /**
- * Return all interfaces that the given class implements as Set,
- * including ones implemented by superclasses.
- * <p>If the class itself is an interface, it gets returned as sole
interface.
- * @param clazz the class to analyze for interfaces
- * @return all interfaces that the given object implements as Set
- */
- public static Set<Class<?>> getAllInterfacesForClassAsSet(Class<?>
clazz) {
- return getAllInterfacesForClassAsSet(clazz, null);
- }
-
- /**
- * Return all interfaces that the given class implements as Set,
- * including ones implemented by superclasses.
- * <p>If the class itself is an interface, it gets returned as sole
interface.
- * @param clazz the class to analyze for interfaces
- * @param classLoader the ClassLoader that the interfaces need to be
visible in
- * (may be {@code null} when accepting all declared interfaces)
- * @return all interfaces that the given object implements as Set
- */
- public static Set<Class<?>> getAllInterfacesForClassAsSet(Class<?>
clazz, ClassLoader classLoader) {
- Objects.requireNonNull(clazz, "Class must not be null");
- if (clazz.isInterface() && isVisible(clazz, classLoader)) {
- return Collections.<Class<?>>singleton(clazz);
- }
- Set<Class<?>> interfaces = new LinkedHashSet<>();
- while (clazz != null) {
- Class<?>[] ifcs = clazz.getInterfaces();
- for (Class<?> ifc : ifcs) {
-
interfaces.addAll(getAllInterfacesForClassAsSet(ifc, classLoader));
- }
- clazz = clazz.getSuperclass();
- }
- return interfaces;
- }
-
- /**
- * Create a composite interface Class for the given interfaces,
- * implementing the given interfaces in one single Class.
- * <p>This implementation builds a JDK proxy class for the given
interfaces.
- * @param interfaces the interfaces to merge
- * @param classLoader the ClassLoader to of 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(interfaces.length==0) throw new
IllegalArgumentException("Interfaces must not be empty");
- Objects.requireNonNull(classLoader, "ClassLoader must not be
null");
- return Proxy.getProxyClass(classLoader, interfaces);
- }
-
- /**
- * Determine the common ancestor current the given classes, if any.
- * @param clazz1 the class to introspect
- * @param clazz2 the other class to introspect
- * @return the common ancestor (i.e. common superclass, one interface
- * extending the other), or {@code null} if none found. If any current
the
- * given classes is {@code null}, the other class will be returned.
- * @since 3.2.6
- */
- public static Class<?> determineCommonAncestor(Class<?> clazz1,
Class<?> clazz2) {
- if (clazz1 == null) {
- return clazz2;
- }
- if (clazz2 == null) {
- return clazz1;
- }
- if (clazz1.isAssignableFrom(clazz2)) {
- return clazz1;
- }
- if (clazz2.isAssignableFrom(clazz1)) {
- return clazz2;
- }
- Class<?> ancestor = clazz1;
- do {
- ancestor = ancestor.getSuperclass();
- if (ancestor == null || Object.class.equals(ancestor)) {
- return null;
- }
- }
- while (!ancestor.isAssignableFrom(clazz2));
- return ancestor;
- }
-
- /**
- * 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 {@code
null},
- * in which case this method will always return {@code 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;
- }
- }
+ if (clazz.isInterface() && isVisible(clazz, classLoader)) {
+ return Collections.<Class<?>>singleton(clazz);
+ }
+ Set<Class<?>> interfaces = new LinkedHashSet<>();
+ while (clazz != null) {
+ Class<?>[] ifcs = clazz.getInterfaces();
+ for (Class<?> ifc : ifcs) {
+ interfaces.addAll(getAllInterfacesForClassAsSet(ifc,
classLoader));
+ }
+ clazz = clazz.getSuperclass();
+ }
+ return interfaces;
+ }
+
+ /**
+ * Create a composite interface Class for the given interfaces,
+ * implementing the given interfaces in one single Class.
+ * <p>This implementation builds a JDK proxy class for the given
interfaces.
+ *
+ * @param interfaces the interfaces to merge
+ * @param classLoader the ClassLoader to of 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 (interfaces.length == 0) {
+ throw new IllegalArgumentException("Interfaces must not be empty");
+ }
+ Objects.requireNonNull(classLoader, "ClassLoader must not be null");
+ return Proxy.getProxyClass(classLoader, interfaces);
+ }
+
+ /**
+ * Determine the common ancestor current the given classes, if any.
+ *
+ * @param clazz1 the class to introspect
+ * @param clazz2 the other class to introspect
+ * @return the common ancestor (i.e. common superclass, one interface
+ * extending the other), or {@code null} if none found. If any current the
+ * given classes is {@code null}, the other class will be returned.
+ * @since 3.2.6
+ */
+ public static Class<?> determineCommonAncestor(Class<?> clazz1, Class<?>
clazz2) {
+ if (clazz1 == null) {
+ return clazz2;
+ }
+ if (clazz2 == null) {
+ return clazz1;
+ }
+ if (clazz1.isAssignableFrom(clazz2)) {
+ return clazz1;
+ }
+ if (clazz2.isAssignableFrom(clazz1)) {
+ return clazz2;
+ }
+ Class<?> ancestor = clazz1;
+ do {
+ ancestor = ancestor.getSuperclass();
+ if (ancestor == null || Object.class.equals(ancestor)) {
+ return null;
+ }
+ }
+ while (!ancestor.isAssignableFrom(clazz2));
+ return ancestor;
+ }
+
+ /**
+ * 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 {@code
null},
+ * in which case this method will always return {@code
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;
+ }
+ }
}