KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > util > ClassUtils


1 /*
2  * Copyright 2002-2007 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.springframework.util;
18
19 import java.beans.Introspector JavaDoc;
20 import java.lang.reflect.Array JavaDoc;
21 import java.lang.reflect.Constructor JavaDoc;
22 import java.lang.reflect.Method JavaDoc;
23 import java.lang.reflect.Modifier JavaDoc;
24 import java.lang.reflect.Proxy JavaDoc;
25 import java.util.ArrayList JavaDoc;
26 import java.util.Arrays JavaDoc;
27 import java.util.Collection JavaDoc;
28 import java.util.Collections JavaDoc;
29 import java.util.HashMap JavaDoc;
30 import java.util.HashSet JavaDoc;
31 import java.util.Iterator JavaDoc;
32 import java.util.List JavaDoc;
33 import java.util.Map JavaDoc;
34 import java.util.Set JavaDoc;
35
36 import org.apache.commons.logging.Log;
37 import org.apache.commons.logging.LogFactory;
38
39 /**
40  * Miscellaneous class utility methods. Mainly for internal use within the
41  * framework; consider Jakarta's Commons Lang for a more comprehensive suite
42  * of class utilities.
43  *
44  * @author Keith Donald
45  * @author Rob Harrop
46  * @author Juergen Hoeller
47  * @since 1.1
48  */

49 public abstract class ClassUtils {
50
51     /** Suffix for array class names */
52     public static final String JavaDoc ARRAY_SUFFIX = "[]";
53
54     /** The package separator character '.' */
55     private static final char PACKAGE_SEPARATOR = '.';
56
57     /** The inner class separator character '$' */
58     private static final char INNER_CLASS_SEPARATOR = '$';
59
60     /** The CGLIB class separator character "$$" */
61     private static final String JavaDoc CGLIB_CLASS_SEPARATOR = "$$";
62
63     /** The ".class" file suffix */
64     private static final String JavaDoc CLASS_FILE_SUFFIX = ".class";
65
66
67     private static final Log logger = LogFactory.getLog(ClassUtils.class);
68
69     /**
70      * Map with primitive wrapper type as key and corresponding primitive
71      * type as value, for example: Integer.class -> int.class.
72      */

73     private static final Map JavaDoc primitiveWrapperTypeMap = new HashMap JavaDoc(8);
74
75     /**
76      * Map with primitive type name as key and corresponding primitive
77      * type as value, for example: "int" -> "int.class".
78      */

79     private static final Map JavaDoc primitiveTypeNameMap = new HashMap JavaDoc(8);
80
81     static {
82         primitiveWrapperTypeMap.put(Boolean JavaDoc.class, boolean.class);
83         primitiveWrapperTypeMap.put(Byte JavaDoc.class, byte.class);
84         primitiveWrapperTypeMap.put(Character JavaDoc.class, char.class);
85         primitiveWrapperTypeMap.put(Double JavaDoc.class, double.class);
86         primitiveWrapperTypeMap.put(Float JavaDoc.class, float.class);
87         primitiveWrapperTypeMap.put(Integer JavaDoc.class, int.class);
88         primitiveWrapperTypeMap.put(Long JavaDoc.class, long.class);
89         primitiveWrapperTypeMap.put(Short JavaDoc.class, short.class);
90
91         for (Iterator JavaDoc it = primitiveWrapperTypeMap.values().iterator(); it.hasNext();) {
92             Class JavaDoc primitiveClass = (Class JavaDoc) it.next();
93             primitiveTypeNameMap.put(primitiveClass.getName(), primitiveClass);
94         }
95     }
96
97
98     /**
99      * Return the default ClassLoader to use: typically the thread context
100      * ClassLoader, if available; the ClassLoader that loaded the ClassUtils
101      * class will be used as fallback.
102      * <p>Call this method if you intend to use the thread context ClassLoader
103      * in a scenario where you absolutely need a non-null ClassLoader reference:
104      * for example, for class path resource loading (but not necessarily for
105      * <code>Class.forName</code>, which accepts a <code>null</code> ClassLoader
106      * reference as well).
107      * @return the default ClassLoader (never <code>null</code>)
108      * @see java.lang.Thread#getContextClassLoader()
109      */

110     public static ClassLoader JavaDoc getDefaultClassLoader() {
111         ClassLoader JavaDoc cl = null;
112         try {
113             cl = Thread.currentThread().getContextClassLoader();
114         }
115         catch (Throwable JavaDoc ex) {
116             logger.debug("Cannot access thread context ClassLoader - falling back to system class loader", ex);
117         }
118         if (cl == null) {
119             // No thread context class loader -> use class loader of this class.
120
cl = ClassUtils.class.getClassLoader();
121         }
122         return cl;
123     }
124
125     /**
126      * Determine whether the {@link Class} identified by the supplied name is present
127      * and can be loaded. Will return <code>false</code> if either the class or
128      * one of its dependencies is not present or cannot be loaded.
129      * @param className the name of the class to check
130      * @return whether the specified class is present
131      */

132     public static boolean isPresent(String JavaDoc className) {
133         return isPresent(className, getDefaultClassLoader());
134     }
135
136     /**
137      * Determine whether the {@link Class} identified by the supplied name is present
138      * and can be loaded. Will return <code>false</code> if either the class or
139      * one of its dependencies is not present or cannot be loaded.
140      * @param className the name of the class to check
141      * @param classLoader the class loader to use
142      * (may be <code>null</code>, which indicates the default class loader)
143      * @return whether the specified class is present
144      */

145     public static boolean isPresent(String JavaDoc className, ClassLoader JavaDoc classLoader) {
146         try {
147             forName(className, classLoader);
148             return true;
149         }
150         catch (Throwable JavaDoc ex) {
151             if (logger.isDebugEnabled()) {
152                 logger.debug("Class [" + className + "] or one of its dependencies is not present: " + ex);
153             }
154             return false;
155         }
156     }
157
158     /**
159      * Replacement for <code>Class.forName()</code> that also returns Class instances
160      * for primitives (like "int") and array class names (like "String[]").
161      * <p>Always uses the default class loader: that is, preferably the thread context
162      * class loader, or the ClassLoader that loaded the ClassUtils class as fallback.
163      * @param name the name of the Class
164      * @return Class instance for the supplied name
165      * @throws ClassNotFoundException if the class was not found
166      * @throws LinkageError if the class file could not be loaded
167      * @see Class#forName(String, boolean, ClassLoader)
168      * @see #getDefaultClassLoader()
169      */

170     public static Class JavaDoc forName(String JavaDoc name) throws ClassNotFoundException JavaDoc, LinkageError JavaDoc {
171         return forName(name, getDefaultClassLoader());
172     }
173
174     /**
175      * Replacement for <code>Class.forName()</code> that also returns Class instances
176      * for primitives (like "int") and array class names (like "String[]").
177      * @param name the name of the Class
178      * @param classLoader the class loader to use
179      * (may be <code>null</code>, which indicates the default class loader)
180      * @return Class instance for the supplied name
181      * @throws ClassNotFoundException if the class was not found
182      * @throws LinkageError if the class file could not be loaded
183      * @see Class#forName(String, boolean, ClassLoader)
184      */

185     public static Class JavaDoc forName(String JavaDoc name, ClassLoader JavaDoc classLoader) throws ClassNotFoundException JavaDoc, LinkageError JavaDoc {
186         Assert.notNull(name, "Name must not be null");
187         Class JavaDoc clazz = resolvePrimitiveClassName(name);
188         if (clazz != null) {
189             return clazz;
190         }
191         if (name.endsWith(ARRAY_SUFFIX)) {
192             // special handling for array class names
193
String JavaDoc elementClassName = name.substring(0, name.length() - ARRAY_SUFFIX.length());
194             Class JavaDoc elementClass = forName(elementClassName, classLoader);
195             return Array.newInstance(elementClass, 0).getClass();
196         }
197         ClassLoader JavaDoc classLoaderToUse = classLoader;
198         if (classLoaderToUse == null) {
199             classLoaderToUse = getDefaultClassLoader();
200         }
201         return classLoaderToUse.loadClass(name);
202     }
203
204     /**
205      * Resolve the given class name into a Class instance. Supports
206      * primitives (like "int") and array class names (like "String[]").
207      * <p>This is effectively equivalent to the <code>forName</code>
208      * method with the same arguments, with the only difference being
209      * the exceptions thrown in case of class loading failure.
210      * @param className the name of the Class
211      * @param classLoader the class loader to use
212      * (may be <code>null</code>, which indicates the default class loader)
213      * @return Class instance for the supplied name
214      * @throws IllegalArgumentException if the class name was not resolvable
215      * (that is, the class could not be found or the class file could not be loaded)
216      * @see #forName(String, ClassLoader)
217      */

218     public static Class JavaDoc resolveClassName(String JavaDoc className, ClassLoader JavaDoc classLoader) throws IllegalArgumentException JavaDoc {
219         try {
220             return forName(className, classLoader);
221         }
222         catch (ClassNotFoundException JavaDoc ex) {
223             throw new IllegalArgumentException JavaDoc("Cannot find class [" + className + "]. Root cause: " + ex);
224         }
225         catch (LinkageError JavaDoc ex) {
226             throw new IllegalArgumentException JavaDoc("Error loading class [" + className +
227                     "]: problem with class file or dependent class. Root cause: " + ex);
228         }
229     }
230
231     /**
232      * Resolve the given class name as primitive class, if appropriate.
233      * @param name the name of the potentially primitive class
234      * @return the primitive class, or <code>null</code> if the name does not denote
235      * a primitive class
236      */

237     public static Class JavaDoc resolvePrimitiveClassName(String JavaDoc name) {
238         Class JavaDoc result = null;
239         // Most class names will be quite long, considering that they
240
// SHOULD sit in a package, so a length check is worthwhile.
241
if (name != null && name.length() <= 8) {
242             // Could be a primitive - likely.
243
result = (Class JavaDoc) primitiveTypeNameMap.get(name);
244         }
245         return result;
246     }
247
248     /**
249      * Return the user-defined class for the given instance: usually simply
250      * the class of the given instance, but the original class in case of a
251      * CGLIB-generated subclass.
252      * @param instance the instance to check
253      * @return the user-defined class
254      */

255     public static Class JavaDoc getUserClass(Object JavaDoc instance) {
256         Assert.notNull(instance, "Instance must not be null");
257         return getUserClass(instance.getClass());
258     }
259
260     /**
261      * Return the user-defined class for the given class: usually simply the given
262      * class, but the original class in case of a CGLIB-generated subclass.
263      * @param clazz the class to check
264      * @return the user-defined class
265      */

266     public static Class JavaDoc getUserClass(Class JavaDoc clazz) {
267         return (clazz != null && clazz.getName().indexOf(CGLIB_CLASS_SEPARATOR) != -1 ?
268                 clazz.getSuperclass() : clazz);
269     }
270
271
272     /**
273      * Get the class name without the qualified package name.
274      * @param className the className to get the short name for
275      * @return the class name of the class without the package name
276      * @throws IllegalArgumentException if the className is empty
277      */

278     public static String JavaDoc getShortName(String JavaDoc className) {
279         Assert.hasLength(className, "Class name must not be empty");
280         int lastDotIndex = className.lastIndexOf(PACKAGE_SEPARATOR);
281         int nameEndIndex = className.indexOf(CGLIB_CLASS_SEPARATOR);
282         if (nameEndIndex == -1) {
283             nameEndIndex = className.length();
284         }
285         String JavaDoc shortName = className.substring(lastDotIndex + 1, nameEndIndex);
286         shortName = shortName.replace(INNER_CLASS_SEPARATOR, PACKAGE_SEPARATOR);
287         return shortName;
288     }
289
290     /**
291      * Get the class name without the qualified package name.
292      * @param clazz the class to get the short name for
293      * @return the class name of the class without the package name
294      */

295     public static String JavaDoc getShortName(Class JavaDoc clazz) {
296         return getShortName(getQualifiedName(clazz));
297     }
298
299     /**
300      * Return the short string name of a Java class in decapitalized
301      * JavaBeans property format.
302      * @param clazz the class
303      * @return the short name rendered in a standard JavaBeans property format
304      * @see java.beans.Introspector#decapitalize(String)
305      */

306     public static String JavaDoc getShortNameAsProperty(Class JavaDoc clazz) {
307         return Introspector.decapitalize(getShortName(clazz));
308     }
309
310     /**
311      * Determine the name of the class file, relative to the containing
312      * package: e.g. "String.class"
313      * @param clazz the class
314      * @return the file name of the ".class" file
315      */

316     public static String JavaDoc getClassFileName(Class JavaDoc clazz) {
317         Assert.notNull(clazz, "Class must not be null");
318         String JavaDoc className = clazz.getName();
319         int lastDotIndex = className.lastIndexOf(PACKAGE_SEPARATOR);
320         return className.substring(lastDotIndex + 1) + CLASS_FILE_SUFFIX;
321     }
322
323     /**
324      * Return the qualified name of the given class: usually simply
325      * the class name, but component type class name + "[]" for arrays.
326      * @param clazz the class
327      * @return the qualified name of the class
328      */

329     public static String JavaDoc getQualifiedName(Class JavaDoc clazz) {
330         Assert.notNull(clazz, "Class must not be null");
331         if (clazz.isArray()) {
332             return getQualifiedNameForArray(clazz);
333         }
334         else {
335             return clazz.getName();
336         }
337     }
338
339     /**
340      * Build a nice qualified name for an array:
341      * component type class name + "[]".
342      * @param clazz the array class
343      * @return a qualified name for the array class
344      */

345     private static String JavaDoc getQualifiedNameForArray(Class JavaDoc clazz) {
346         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
347         while (clazz.isArray()) {
348             clazz = clazz.getComponentType();
349             buffer.append(ClassUtils.ARRAY_SUFFIX);
350         }
351         buffer.insert(0, clazz.getName());
352         return buffer.toString();
353     }
354
355     /**
356      * Return the qualified name of the given method, consisting of
357      * fully qualified interface/class name + "." + method name.
358      * @param method the method
359      * @return the qualified name of the method
360      */

361     public static String JavaDoc getQualifiedMethodName(Method JavaDoc method) {
362         Assert.notNull(method, "Method must not be null");
363         return method.getDeclaringClass().getName() + "." + method.getName();
364     }
365
366
367     /**
368      * Determine whether the given class has a constructor with the given signature.
369      * <p>Essentially translates <code>NoSuchMethodException</code> to "false".
370      * @param clazz the clazz to analyze
371      * @param paramTypes the parameter types of the method
372      * @return whether the class has a corresponding constructor
373      * @see java.lang.Class#getMethod
374      */

375     public static boolean hasConstructor(Class JavaDoc clazz, Class JavaDoc[] paramTypes) {
376         return (getConstructorIfAvailable(clazz, paramTypes) != null);
377     }
378
379     /**
380      * Determine whether the given class has a constructor with the given signature,
381      * and return it if available (else return <code>null</code>).
382      * <p>Essentially translates <code>NoSuchMethodException</code> to <code>null</code>.
383      * @param clazz the clazz to analyze
384      * @param paramTypes the parameter types of the method
385      * @return the constructor, or <code>null</code> if not found
386      * @see java.lang.Class#getConstructor
387      */

388     public static Constructor JavaDoc getConstructorIfAvailable(Class JavaDoc clazz, Class JavaDoc[] paramTypes) {
389         Assert.notNull(clazz, "Class must not be null");
390         try {
391             return clazz.getConstructor(paramTypes);
392         }
393         catch (NoSuchMethodException JavaDoc ex) {
394             return null;
395         }
396     }
397
398     /**
399      * Determine whether the given class has a method with the given signature.
400      * <p>Essentially translates <code>NoSuchMethodException</code> to "false".
401      * @param clazz the clazz to analyze
402      * @param methodName the name of the method
403      * @param paramTypes the parameter types of the method
404      * @return whether the class has a corresponding method
405      * @see java.lang.Class#getMethod
406      */

407     public static boolean hasMethod(Class JavaDoc clazz, String JavaDoc methodName, Class JavaDoc[] paramTypes) {
408         return (getMethodIfAvailable(clazz, methodName, paramTypes) != null);
409     }
410
411     /**
412      * Determine whether the given class has a method with the given signature,
413      * and return it if available (else return <code>null</code>).
414      * <p>Essentially translates <code>NoSuchMethodException</code> to <code>null</code>.
415      * @param clazz the clazz to analyze
416      * @param methodName the name of the method
417      * @param paramTypes the parameter types of the method
418      * @return the method, or <code>null</code> if not found
419      * @see java.lang.Class#getMethod
420      */

421     public static Method JavaDoc getMethodIfAvailable(Class JavaDoc clazz, String JavaDoc methodName, Class JavaDoc[] paramTypes) {
422         Assert.notNull(clazz, "Class must not be null");
423         Assert.notNull(methodName, "Method name must not be null");
424         try {
425             return clazz.getMethod(methodName, paramTypes);
426         }
427         catch (NoSuchMethodException JavaDoc ex) {
428             return null;
429         }
430     }
431
432     /**
433      * Return the number of methods with a given name (with any argument types),
434      * for the given class and/or its superclasses. Includes non-public methods.
435      * @param clazz the clazz to check
436      * @param methodName the name of the method
437      * @return the number of methods with the given name
438      */

439     public static int getMethodCountForName(Class JavaDoc clazz, String JavaDoc methodName) {
440         Assert.notNull(clazz, "Class must not be null");
441         Assert.notNull(methodName, "Method name must not be null");
442         int count = 0;
443         for (int i = 0; i < clazz.getDeclaredMethods().length; i++) {
444             Method JavaDoc method = clazz.getDeclaredMethods()[i];
445             if (methodName.equals(method.getName())) {
446                 count++;
447             }
448         }
449         Class JavaDoc[] ifcs = clazz.getInterfaces();
450         for (int i = 0; i < ifcs.length; i++) {
451             count += getMethodCountForName(ifcs[i], methodName);
452         }
453         if (clazz.getSuperclass() != null) {
454             count += getMethodCountForName(clazz.getSuperclass(), methodName);
455         }
456         return count;
457     }
458
459     /**
460      * Does the given class and/or its superclasses at least have one or more
461      * methods (with any argument types)? Includes non-public methods.
462      * @param clazz the clazz to check
463      * @param methodName the name of the method
464      * @return whether there is at least one method with the given name
465      */

466     public static boolean hasAtLeastOneMethodWithName(Class JavaDoc clazz, String JavaDoc methodName) {
467         Assert.notNull(clazz, "Class must not be null");
468         Assert.notNull(methodName, "Method name must not be null");
469         for (int i = 0; i < clazz.getDeclaredMethods().length; i++) {
470             Method JavaDoc method = clazz.getDeclaredMethods()[i];
471             if (method.getName().equals(methodName)) {
472                 return true;
473             }
474         }
475         Class JavaDoc[] ifcs = clazz.getInterfaces();
476         for (int i = 0; i < ifcs.length; i++) {
477             if (hasAtLeastOneMethodWithName(ifcs[i], methodName)) {
478                 return true;
479             }
480         }
481         return (clazz.getSuperclass() != null && hasAtLeastOneMethodWithName(clazz.getSuperclass(), methodName));
482     }
483
484     /**
485      * Return a static method of a class.
486      * @param methodName the static method name
487      * @param clazz the class which defines the method
488      * @param args the parameter types to the method
489      * @return the static method, or <code>null</code> if no static method was found
490      * @throws IllegalArgumentException if the method name is blank or the clazz is null
491      */

492     public static Method JavaDoc getStaticMethod(Class JavaDoc clazz, String JavaDoc methodName, Class JavaDoc[] args) {
493         Assert.notNull(clazz, "Class must not be null");
494         Assert.notNull(methodName, "Method name must not be null");
495         try {
496             Method JavaDoc method = clazz.getDeclaredMethod(methodName, args);
497             if ((method.getModifiers() & Modifier.STATIC) != 0) {
498                 return method;
499             }
500         }
501         catch (NoSuchMethodException JavaDoc ex) {
502         }
503         return null;
504     }
505
506
507     /**
508      * Check if the given class represents a primitive wrapper,
509      * i.e. Boolean, Byte, Character, Short, Integer, Long, Float, or Double.
510      */

511     public static boolean isPrimitiveWrapper(Class JavaDoc clazz) {
512         Assert.notNull(clazz, "Class must not be null");
513         return primitiveWrapperTypeMap.containsKey(clazz);
514     }
515
516     /**
517      * Check if the given class represents a primitive (i.e. boolean, byte,
518      * char, short, int, long, float, or double) or a primitive wrapper
519      * (i.e. Boolean, Byte, Character, Short, Integer, Long, Float, or Double).
520      */

521     public static boolean isPrimitiveOrWrapper(Class JavaDoc clazz) {
522         Assert.notNull(clazz, "Class must not be null");
523         return (clazz.isPrimitive() || isPrimitiveWrapper(clazz));
524     }
525
526     /**
527      * Check if the given class represents an array of primitives,
528      * i.e. boolean, byte, char, short, int, long, float, or double.
529      */

530     public static boolean isPrimitiveArray(Class JavaDoc clazz) {
531         Assert.notNull(clazz, "Class must not be null");
532         return (clazz.isArray() && clazz.getComponentType().isPrimitive());
533     }
534
535     /**
536      * Check if the given class represents an array of primitive wrappers,
537      * i.e. Boolean, Byte, Character, Short, Integer, Long, Float, or Double.
538      */

539     public static boolean isPrimitiveWrapperArray(Class JavaDoc clazz) {
540         Assert.notNull(clazz, "Class must not be null");
541         return (clazz.isArray() && isPrimitiveWrapper(clazz.getComponentType()));
542     }
543
544     /**
545      * Determine if the given target type is assignable from the given value
546      * type, assuming setting by reflection. Considers primitive wrapper
547      * classes as assignable to the corresponding primitive types.
548      * @param targetType the target type
549      * @param valueType the value type that should be assigned to the target type
550      * @return if the target type is assignable from the value type
551      */

552     public static boolean isAssignable(Class JavaDoc targetType, Class JavaDoc valueType) {
553         Assert.notNull(targetType, "Target type must not be null");
554         Assert.notNull(valueType, "Value type must not be null");
555         return (targetType.isAssignableFrom(valueType) ||
556                 targetType.equals(primitiveWrapperTypeMap.get(valueType)));
557     }
558
559     /**
560      * Determine if the given type is assignable from the given value,
561      * assuming setting by reflection. Considers primitive wrapper classes
562      * as assignable to the corresponding primitive types.
563      * @param type the target type
564      * @param value the value that should be assigned to the type
565      * @return if the type is assignable from the value
566      */

567     public static boolean isAssignableValue(Class JavaDoc type, Object JavaDoc value) {
568         Assert.notNull(type, "Type must not be null");
569         return (value != null ? isAssignable(type, value.getClass()) : !type.isPrimitive());
570     }
571
572
573     /**
574      * Return a path suitable for use with <code>ClassLoader.getResource</code>
575      * (also suitable for use with <code>Class.getResource</code> by prepending a
576      * slash ('/') to the return value. Built by taking the package of the specified
577      * class file, converting all dots ('.') to slashes ('/'), adding a trailing slash
578      * if necesssary, and concatenating the specified resource name to this.
579      * <br/>As such, this function may be used to build a path suitable for
580      * loading a resource file that is in the same package as a class file,
581      * although {@link org.springframework.core.io.ClassPathResource} is usually
582      * even more convenient.
583      * @param clazz the Class whose package will be used as the base
584      * @param resourceName the resource name to append. A leading slash is optional.
585      * @return the built-up resource path
586      * @see java.lang.ClassLoader#getResource
587      * @see java.lang.Class#getResource
588      */

589     public static String JavaDoc addResourcePathToPackagePath(Class JavaDoc clazz, String JavaDoc resourceName) {
590         Assert.notNull(resourceName, "Resource name must not be null");
591         if (!resourceName.startsWith("/")) {
592             return classPackageAsResourcePath(clazz) + "/" + resourceName;
593         }
594         return classPackageAsResourcePath(clazz) + resourceName;
595     }
596
597     /**
598      * Given an input class object, return a string which consists of the
599      * class's package name as a pathname, i.e., all dots ('.') are replaced by
600      * slashes ('/'). Neither a leading nor trailing slash is added. The result
601      * could be concatenated with a slash and the name of a resource, and fed
602      * directly to <code>ClassLoader.getResource()</code>. For it to be fed to
603      * <code>Class.getResource</code> instead, a leading slash would also have
604      * to be prepended to the returned value.
605      * @param clazz the input class. A <code>null</code> value or the default
606      * (empty) package will result in an empty string ("") being returned.
607      * @return a path which represents the package name
608      * @see ClassLoader#getResource
609      * @see Class#getResource
610      */

611     public static String JavaDoc classPackageAsResourcePath(Class JavaDoc clazz) {
612         if (clazz == null) {
613             return "";
614         }
615         String JavaDoc className = clazz.getName();
616         int packageEndIndex = className.lastIndexOf('.');
617         if (packageEndIndex == -1) {
618             return "";
619         }
620         String JavaDoc packageName = className.substring(0, packageEndIndex);
621         return packageName.replace('.', '/');
622     }
623
624     /**
625      * Build a String that consists of the names of the classes/interfaces
626      * in the given array.
627      * <p>Basically like <code>AbstractCollection.toString()</code>, but stripping
628      * the "class "/"interface " prefix before every class name.
629      * @param classes a Collection of Class objects (may be <code>null</code>)
630      * @return a String of form "[com.foo.Bar, com.foo.Baz]"
631      * @see java.util.AbstractCollection#toString()
632      */

633     public static String JavaDoc classNamesToString(Class JavaDoc[] classes) {
634         return classNamesToString(Arrays.asList(classes));
635     }
636
637     /**
638      * Build a String that consists of the names of the classes/interfaces
639      * in the given collection.
640      * <p>Basically like <code>AbstractCollection.toString()</code>, but stripping
641      * the "class "/"interface " prefix before every class name.
642      * @param classes a Collection of Class objects (may be <code>null</code>)
643      * @return a String of form "[com.foo.Bar, com.foo.Baz]"
644      * @see java.util.AbstractCollection#toString()
645      */

646     public static String JavaDoc classNamesToString(Collection JavaDoc classes) {
647         if (CollectionUtils.isEmpty(classes)) {
648             return "[]";
649         }
650         StringBuffer JavaDoc sb = new StringBuffer JavaDoc("[");
651         for (Iterator JavaDoc it = classes.iterator(); it.hasNext(); ) {
652             Class JavaDoc clazz = (Class JavaDoc) it.next();
653             sb.append(clazz.getName());
654             if (it.hasNext()) {
655                 sb.append(", ");
656             }
657         }
658         sb.append("]");
659         return sb.toString();
660     }
661
662
663     /**
664      * Return all interfaces that the given instance implements as array,
665      * including ones implemented by superclasses.
666      * @param instance the instance to analyse for interfaces
667      * @return all interfaces that the given instance implements as array
668      */

669     public static Class JavaDoc[] getAllInterfaces(Object JavaDoc instance) {
670         Assert.notNull(instance, "Instance must not be null");
671         return getAllInterfacesForClass(instance.getClass());
672     }
673
674     /**
675      * Return all interfaces that the given class implements as array,
676      * including ones implemented by superclasses.
677      * <p>If the class itself is an interface, it gets returned as sole interface.
678      * @param clazz the class to analyse for interfaces
679      * @return all interfaces that the given object implements as array
680      */

681     public static Class JavaDoc[] getAllInterfacesForClass(Class JavaDoc clazz) {
682         Assert.notNull(clazz, "Class must not be null");
683         if (clazz.isInterface()) {
684             return new Class JavaDoc[] {clazz};
685         }
686         List JavaDoc interfaces = new ArrayList JavaDoc();
687         while (clazz != null) {
688             for (int i = 0; i < clazz.getInterfaces().length; i++) {
689                 Class JavaDoc ifc = clazz.getInterfaces()[i];
690                 if (!interfaces.contains(ifc)) {
691                     interfaces.add(ifc);
692                 }
693             }
694             clazz = clazz.getSuperclass();
695         }
696         return (Class JavaDoc[]) interfaces.toArray(new Class JavaDoc[interfaces.size()]);
697     }
698
699     /**
700      * Return all interfaces that the given instance implements as Set,
701      * including ones implemented by superclasses.
702      * @param instance the instance to analyse for interfaces
703      * @return all interfaces that the given instance implements as Set
704      */

705     public static Set JavaDoc getAllInterfacesAsSet(Object JavaDoc instance) {
706         Assert.notNull(instance, "Instance must not be null");
707         return getAllInterfacesForClassAsSet(instance.getClass());
708     }
709
710     /**
711      * Return all interfaces that the given class implements as Set,
712      * including ones implemented by superclasses.
713      * <p>If the class itself is an interface, it gets returned as sole interface.
714      * @param clazz the class to analyse for interfaces
715      * @return all interfaces that the given object implements as Set
716      */

717     public static Set JavaDoc getAllInterfacesForClassAsSet(Class JavaDoc clazz) {
718         Assert.notNull(clazz, "Class must not be null");
719         if (clazz.isInterface()) {
720             return Collections.singleton(clazz);
721         }
722         Set JavaDoc interfaces = new HashSet JavaDoc();
723         while (clazz != null) {
724             for (int i = 0; i < clazz.getInterfaces().length; i++) {
725                 Class JavaDoc ifc = clazz.getInterfaces()[i];
726                 interfaces.add(ifc);
727             }
728             clazz = clazz.getSuperclass();
729         }
730         return interfaces;
731     }
732
733     /**
734      * Create a composite interface Class for the given interfaces,
735      * implementing the given interfaces in one single Class.
736      * <p>This implementation builds a JDK proxy class for the given interfaces.
737      * @param interfaces the interfaces to merge
738      * @param classLoader the ClassLoader to create the composite Class in
739      * @return the merged interface as Class
740      * @see java.lang.reflect.Proxy#getProxyClass
741      */

742     public static Class JavaDoc createCompositeInterface(Class JavaDoc[] interfaces, ClassLoader JavaDoc classLoader) {
743         Assert.notEmpty(interfaces, "Interfaces must not be empty");
744         Assert.notNull(classLoader, "ClassLoader must not be null");
745         return Proxy.getProxyClass(classLoader, interfaces);
746     }
747
748 }
749
Popular Tags