001: package org.andromda.core.common;
002:
003: import java.lang.reflect.Field;
004: import java.lang.reflect.Modifier;
005: import java.net.URL;
006: import java.util.ArrayList;
007: import java.util.Arrays;
008: import java.util.Collection;
009: import java.util.Iterator;
010: import java.util.LinkedHashSet;
011: import java.util.List;
012: import java.util.Set;
013:
014: import org.apache.commons.collections.CollectionUtils;
015: import org.apache.commons.lang.StringUtils;
016:
017: /**
018: * Contains utilities for dealing with classes.
019: *
020: * @author Chad Brandon
021: */
022: public class ClassUtils extends org.apache.commons.lang.ClassUtils {
023: /**
024: * Creates a new instance of the class having the given <code>className</code>.
025: *
026: * @param className the name of the class to instantiate.
027: * @return Object the new instance
028: */
029: public static Object newInstance(final String className) {
030: try {
031: return loadClass(className).newInstance();
032: } catch (final Throwable throwable) {
033: throw new ClassUtilsException(throwable);
034: }
035: }
036:
037: /**
038: * Creates a new instance of the class given the <code>type</code>.
039: *
040: * @param type the type from which to instantiate the new instance.
041: * @return Object the new instance
042: */
043: public static Object newInstance(final Class type) {
044: try {
045: return type != null ? type.newInstance() : null;
046: } catch (final Throwable throwable) {
047: throw new ClassUtilsException(throwable);
048: }
049: }
050:
051: /**
052: * Loads and returns the class having the className. Will load but normal classes and the classes representing
053: * primatives.
054: *
055: * @param className the name of the class to load.
056: * @return Class the loaded class
057: */
058: public static Class loadClass(String className) {
059: ExceptionUtils.checkEmpty("className", className);
060: className = StringUtils.trimToNull(className);
061:
062: // get rid of any array notation
063: className = StringUtils.replace(className, "[]", "");
064:
065: final ClassLoader loader = getClassLoader();
066: Class loadedClass;
067: try {
068: // check and see if its a primitive and if so convert it
069: if (ClassUtils.isPrimitiveType(className)) {
070: loadedClass = getPrimitiveClass(className, loader);
071: } else {
072: loadedClass = loader.loadClass(className);
073: }
074: } catch (final Throwable throwable) {
075: throw new ClassUtilsException(throwable);
076: }
077: return loadedClass;
078: }
079:
080: /**
081: * Gets the appropriate class loader instance.
082: *
083: * @return the class loader.
084: */
085: public static ClassLoader getClassLoader() {
086: ClassLoader loader = Thread.currentThread()
087: .getContextClassLoader();
088: if (loader == null) {
089: loader = ClassUtils.class.getClassLoader();
090: Thread.currentThread().setContextClassLoader(loader);
091: }
092: return loader;
093: }
094:
095: /**
096: * <p> Returns the type class name for a Java primitive.
097: * </p>
098: *
099: * @param name a <code>String</code> with the name of the type
100: * @param loader the loader to use.
101: * @return a <code>String</code> with the name of the corresponding
102: * java.lang wrapper class if <code>name</code> is a Java
103: * primitive type; <code>false</code> if not
104: */
105: protected static Class getPrimitiveClass(final String name,
106: final ClassLoader loader) {
107: ExceptionUtils.checkEmpty("name", name);
108: ExceptionUtils.checkNull("loader", loader);
109:
110: Class primitiveClass = null;
111: if (isPrimitiveType(name) && !name.equals("void")) {
112: final String className;
113: if ("char".equals(name)) {
114: className = "java.lang.Character";
115: } else if ("int".equals(name)) {
116: className = "java.lang.Integer";
117: } else {
118: className = "java.lang." + StringUtils.capitalize(name);
119: }
120:
121: try {
122: if (StringUtils.isNotEmpty(className)) {
123: Field field = loader.loadClass(className).getField(
124: "TYPE");
125: primitiveClass = (Class) field.get(null);
126: }
127: } catch (final Exception exception) {
128: throw new ClassUtilsException(exception);
129: }
130: }
131: return primitiveClass;
132: }
133:
134: /**
135: * Returns a collection of all static fields values for the given
136: * <code>clazz</code> and <code>type</code> of field.
137: *
138: * @param clazz the Class from which to retrieve the static fields
139: * @param type the type of static fields to retrieve, if null all are retrieved
140: * @return Collection the collection of static field values.
141: */
142: public static Collection getStaticFieldValues(final Class clazz,
143: final Class type) throws IllegalAccessException {
144: ExceptionUtils.checkNull("clazz", clazz);
145: final Field[] fields = clazz.getFields();
146: int fieldsNum = fields.length;
147:
148: final List values = new ArrayList();
149: Field field;
150: int modifiers;
151: for (int ctr = 0; ctr < fieldsNum; ctr++) {
152: field = fields[ctr];
153: modifiers = field.getModifiers();
154: if (Modifier.isStatic(modifiers)) {
155: if (type != null) {
156: if (type == field.getType()) {
157: values.add(fields[ctr].get(null));
158: }
159: } else {
160: values.add(fields[ctr].get(null));
161: }
162: }
163: }
164: return values;
165: }
166:
167: /**
168: * Retrieves all interfaces for the given <code>className</code> (including <code>className</code>
169: * itself, assuming it's an interface as well).
170: *
171: * @param className the root interface className
172: * @return a list containing all interfaces ordered from the root down.
173: */
174: public static List getInterfaces(final String className) {
175: final List interfaces = new ArrayList();
176: if (className != null && className.trim().length() > 0) {
177: interfaces.addAll(getInterfaces(ClassUtils
178: .loadClass(className.trim())));
179: }
180: return interfaces;
181: }
182:
183: /**
184: * Retrieves all interfaces for the given <code>clazz</code> (including <code>clazz</code>
185: * itself, assuming it's an interface as well).
186: *
187: * @param clazz the root interface class
188: * @return a list containing all interfaces ordered from the root down.
189: */
190: public static List getInterfaces(final Class clazz) {
191: final List interfaces = new ArrayList();
192: if (clazz != null) {
193: interfaces.addAll(ClassUtils.getAllInterfaces(clazz));
194: if (clazz.isInterface()) {
195: interfaces.add(0, clazz);
196: }
197: }
198: return interfaces;
199: }
200:
201: /**
202: * Gets the interfaces for the given <code>className</code> in reverse order.
203: *
204: * @param className the name of the class for which to retrieve the interfaces
205: * @return the array containing the reversed interfaces.
206: */
207: public static Class[] getInterfacesReversed(final String className) {
208: Class[] interfaces = (Class[]) getInterfaces(className)
209: .toArray(new Class[0]);
210: if (interfaces != null && interfaces.length > 0) {
211: CollectionUtils.reverseArray(interfaces);
212: }
213: return interfaces;
214: }
215:
216: /**
217: * <p/>
218: * Checks if a given type name is a Java primitive type. </p>
219: *
220: * @param name a <code>String</code> with the name of the type
221: * @return <code>true</code> if <code>name</code> is a Java primitive type; <code>false</code> if not
222: */
223: protected static boolean isPrimitiveType(final String name) {
224: return ("void".equals(name) || "char".equals(name)
225: || "byte".equals(name) || "short".equals(name)
226: || "int".equals(name) || "long".equals(name)
227: || "float".equals(name) || "double".equals(name) || "boolean"
228: .equals(name));
229: }
230:
231: /**
232: * The suffix for class files.
233: */
234: public static final String CLASS_EXTENSION = ".class";
235:
236: /**
237: * Searches the contents of the <code>directoryUri</code> and returns the first
238: * Class found that is of the given <code>type</code>.
239: *
240: * @param directoryUris the URIs to search, ie. directories or archives.
241: * @param type the type to find.
242: * @return the class or null if not found.
243: */
244: public static Class findClassOfType(final URL directoryUris[],
245: final Class type) {
246: Class found = null;
247: if (directoryUris != null && directoryUris.length > 0) {
248: final int numberOfDirectoryUris = directoryUris.length;
249: for (int ctr = 0; ctr < numberOfDirectoryUris; ctr++) {
250: final URL directoryUri = directoryUris[ctr];
251: final List contents = ResourceUtils
252: .getDirectoryContents(directoryUri, false, null);
253: for (final Iterator iterator = contents.iterator(); iterator
254: .hasNext();) {
255: final String path = (String) iterator.next();
256: if (path.endsWith(CLASS_EXTENSION)) {
257: final String typeName = StringUtils.replace(
258: ResourceUtils.normalizePath(path)
259: .replace('/', '.'),
260: CLASS_EXTENSION, "");
261: try {
262: final Class loadedClass = getClassLoader()
263: .loadClass(typeName);
264: if (type.isAssignableFrom(loadedClass)) {
265: found = loadedClass;
266: break;
267: }
268: } catch (final ClassNotFoundException exception) {
269: // - ignore, means the file wasn't a class
270: }
271: }
272: }
273: }
274: }
275: return found;
276: }
277:
278: /**
279: * Loads all methods from the given <code>clazz</code> (this includes
280: * all super class methods, public, private and protected).
281: *
282: * @param clazz the class to retrieve the methods.
283: * @return the loaded methods.
284: */
285: public static List getAllMethods(final Class clazz) {
286: final Set methods = new LinkedHashSet();
287: loadMethods(clazz, methods);
288: return new ArrayList(methods);
289: }
290:
291: /**
292: * Loads all methods from the given <code>clazz</code> (this includes
293: * all super class methods).
294: *
295: * @param methods the list to load full of methods.
296: * @param clazz the class to retrieve the methods.
297: */
298: private static void loadMethods(final Class clazz, final Set methods) {
299: methods.addAll(Arrays.asList(clazz.getDeclaredMethods()));
300: if (clazz.getSuperclass() != null) {
301: loadMethods(clazz.getSuperclass(), methods);
302: }
303: }
304:
305: /**
306: * Indicates whether or not a class of the given <code>type</code>
307: * is present in one of the given <code>directoryUris</code>.
308: *
309: * @param directoryUris the URIs to search, ie. directories or archives.
310: * @param type the type to check.
311: * @return true/false.
312: */
313: public static boolean isClassOfTypePresent(
314: final URL directoryUris[], final Class type) {
315: return ClassUtils.findClassOfType(directoryUris, type) != null;
316: }
317: }
|