/** * */ package com.trendrr.oss; import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.net.JarURLConnection; import java.net.URL; import java.net.URLDecoder; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.List; import java.util.jar.JarEntry; import java.util.jar.JarFile; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * @author dustin * */ public class Reflection { protected static Log log = LogFactory.getLog(Reflection.class); public static void setter(Object obj, String name, Object input) { try { obj.getClass().getMethod("set" + StringHelper.capitalize(name), input.getClass()).invoke(obj, input); } catch (Exception x) { // log.info("Caught", x); } } /** * this does a attempt to find the method you are looking for, it will look at every * method in the class and run any that match the name against the inputs. This approach is * slightly slower then the execute method, which suffers from requiring the inputs to match the class * of the inputs exactly. * * * @param obj * @param method * @param input */ public static Object exec(Object obj, String method, Object ... inputs) throws Exception{ Exception lastException = null; for (Method m : obj.getClass().getMethods()) { if (m.getName().equals(method)) { try { return m.invoke(obj, inputs); } catch (Exception x) { lastException = x; } } } if (lastException != null) throw lastException; throw new java.lang.NoSuchMethodException("No method found with name: " + method); } /** * This will execute the requested method on the specified object. note, this does not search superclasses * @param obj * @param method * @param inputs * @return * @throws Exception */ public static Object execute(Object obj, String method, Object ... inputs) throws Exception{ if (inputs.length == 1) { exec(obj, method, inputs[0]); return null; } try { Class[] classes = new Class[inputs.length]; int i=0; for (Object o : inputs) { classes[i] = o.getClass(); i++; } return obj.getClass().getMethod(method, classes).invoke(obj, inputs); } catch (java.lang.reflect.InvocationTargetException ex) { if (ex.getCause() != null && ex.getCause() instanceof Exception) { throw (Exception)ex.getCause(); } throw ex; } catch (Exception x) { throw x; } } /** * accesses a getter. will return null if the getter is not found, else returns whatever the * data is. * @param obj * @param name * @return */ public static Object getter(Object obj, String name) { // log.warn("Trying to get getter: " + name + " for " + obj); try { if (!name.startsWith("get")) { name = "get" + StringHelper.capitalize(name); } return obj.getClass().getMethod(name).invoke(obj); } catch (java.lang.NoClassDefFoundError ex) { log.warn("Caught and swallowed (likely an unresolved dependancy) while trying to use getter: " + name, ex); } catch (NoSuchMethodException x) { // x.printStackTrace(); } catch (Throwable x) { log.info("Caught and swalled (trying to use getter: " + name + ")", x); } return null; } public static boolean hasGetter(Object obj, String name) { try { obj.getClass().getMethod("get" + StringHelper.capitalize(name)); return true; } catch (NoSuchMethodException x) { } return false; } public static boolean hasMethod(Object obj, String name, Class ...params) { try { obj.getClass().getMethod(name, params); return true; } catch (NoSuchMethodException x) { } return false; } /** * gets an instance of the specified class. cls is assumed to be the base class. * @param cls * @param className * @param params * @return */ public static <T> T instance(Class<T> cls, String className, Object ... params ) { try { Class[] paramTypes = new Class[params.length]; for (int i=0; i < params.length; i++) { paramTypes[i] = params[i].getClass(); } Class newcls = Class.forName(className); Constructor<T> cstr = newcls.getConstructor(paramTypes); T instance = (T)cstr.newInstance(params); return instance; } catch (Throwable x) { // log.info("Caught Pie", x); // x.printStackTrace(); } return null; } public static <T> T instance(Class<T> cls, Object ... params ) { try { Class[] paramTypes = new Class[params.length]; for (int i=0; i < params.length; i++) { paramTypes[i] = params[i].getClass(); } Constructor<T> cstr = cls.getConstructor(paramTypes); T instance = (T)cstr.newInstance(params); return instance; } catch (Throwable x) { // log.info("Caught Pie", x); // x.printStackTrace(); } return null; } public static <T> List<T> instances(Class<T> cls, String packageName, boolean recur, Object ... params) { try { // log.info("Looking at package : " + packageName); List<Class> classes = findClasses(packageName, recur); List<T> instances = new ArrayList<T>(); for (Class c : classes) { // log.info("got class: " + c + " classessize: " + classes.size()); if (cls.isAssignableFrom(c)) { T inst = (T)instance(c, params); if (inst != null) { instances.add(inst); } else { // log.info("Unable to instantiate: " + c); } } } // log.info("returning instances: " + instances); return instances; } catch (Throwable x) { // log.info("Caught", x); } return null; } /** * returns a defualt instance of the passedc in classname. * cls is assumed to be the base class. * * @param <T> * @param cls * @param className * @return * @throws Exception */ public static <T> T defaultInstance(Class<T> cls, String className) throws Exception { try { Class newcls = Class.forName(className); Constructor<T> cstr = newcls.getConstructor(); T instance = (T)cstr.newInstance(); return instance; } catch (Exception x) { throw x; } catch (Throwable x) { throw new Exception(x); } } /** * searches the given packagename for any implementations of class t and returns new instances for each. * @param <T> * @param cls * @param packageName * @param recure * @return * @throws Exception */ public static <T> List<T> defaultInstances(Class<T> cls, String packageName, boolean recur) throws Exception { try { List<Class> classes = findClasses(packageName, recur); List<T> instances = new ArrayList<T>(); for (Class c : classes) { if (c.isInterface() || Modifier.isAbstract( c.getModifiers() )) { //skipping continue; } if (cls.isAssignableFrom(c)) { instances.add((T)defaultInstance(c)); } } return instances; } catch (Exception x) { throw x; } catch (Throwable x) { throw new Exception(x); } } public static <T> T defaultInstance(Class<T> cls) throws Exception { try { Constructor<T> cstr = cls.getConstructor(); T instance = (T)cstr.newInstance(); return instance; } catch (Exception x) { throw x; } catch (Throwable x) { throw new Exception(x); } } public static Object defaultInstance(String className) throws Exception { try { Class newcls = Class.forName(className); Constructor cstr = newcls.getConstructor(); return cstr.newInstance(); } catch (Exception x) { throw x; } catch (Throwable x) { throw new Exception(x); } } /** * returns all the classes of type cls (or some subclass) within the specified package. * @param cls * @param pckgname * @param recur * @return * @throws ClassNotFoundException */ public static List<Class> findClassesOfType(Class cls, String pckgname, boolean recur) throws ClassNotFoundException { List<Class> classes = findClasses(pckgname, recur); List<Class> retList = new ArrayList<Class>(); for (Class c : classes) { if (cls.isAssignableFrom(c)) { retList.add(c); } } return retList; } /** * Gets a list of all the classes in the given package. * * * references: * http://forums.sun.com/thread.jspa?threadID=341935 * http://www.javaworld.com/javaworld/javatips/jw-javatip113.html?page=2 * * @param pckgname package name ex: 'com.trendrr.common' * @param recur should list sub packages as well? * @return * @throws ClassNotFoundException */ public static List<Class> findClasses(String pckgname, boolean recur) throws ClassNotFoundException { // This will hold a list of directories matching the pckgname. //There may be more than one if a package is split over multiple jars/paths ArrayList<Class> classes = new ArrayList<Class>(); ArrayList<File> directories = new ArrayList<File>(); try { ClassLoader cld = Thread.currentThread().getContextClassLoader(); if (cld == null) { throw new ClassNotFoundException("Can't get class loader."); } // Ask for all resources for the path Enumeration<URL> resources = cld.getResources(pckgname.replace('.', '/')); while (resources.hasMoreElements()) { URL res = resources.nextElement(); if (res.getProtocol().equalsIgnoreCase("jar")){ JarURLConnection conn = (JarURLConnection) res.openConnection(); JarFile jar = conn.getJarFile(); for (JarEntry e:Collections.list(jar.entries())){ if (e.getName().startsWith(pckgname.replace('.', '/')) && e.getName().endsWith(".class") && !e.getName().contains("$")){ String className = e.getName().replace("/",".").substring(0,e.getName().length() - 6); try { classes.add(Class.forName(className)); } catch (java.lang.NoClassDefFoundError ex) { log.warn("Caught and swallowed (likely an unresolved dependancy) while trying to add: " + className, ex); } } } }else directories.add(new File(URLDecoder.decode(res.getPath(), "UTF-8"))); } } catch (NullPointerException x) { throw new ClassNotFoundException(pckgname + " does not appear to be " + "a valid package (Null pointer exception)"); } catch (UnsupportedEncodingException encex) { throw new ClassNotFoundException(pckgname + " does not appear to be " + "a valid package (Unsupported encoding)"); } catch (IOException ioex) { throw new ClassNotFoundException("IOException was thrown when trying " + "to get all resources for " + pckgname); } for (File directory : directories) { directoryClasses(classes, directory, pckgname, recur); } return classes; } private static void directoryClasses(ArrayList<Class> classes, File dir, String pckgname, boolean recur) throws ClassNotFoundException{ // log.debug("looking at file " + dir.getAbsolutePath()); if (dir.exists()) { // Get the list of the files contained in the package File[] files = dir.listFiles(); for (int i = 0; i < files.length; i++) { String filename = files[i].getName(); // we are only interested in .class files if (filename.endsWith(".class")) { // removes the .class extension String className = pckgname + '.' + filename.substring(0, filename.length() - 6); try { classes.add(Class.forName(className)); } catch (NoClassDefFoundError ex) { log.warn("Caught and swallowed (likely an unresolved dependancy) while trying to add: " + className, ex); } } if (files[i].isDirectory() && recur) { directoryClasses(classes, files[i], pckgname + '.' + filename, recur); } } } } }