Reflect Helper class
24/03/2010
import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * Utility class for reflect purpose. */ public final class ReflectHelper { /** * Empty private constructor for util class. */ private ReflectHelper() { // Empty private constructor for util class. } /** Constant meaning accessor type setter. */ public static final String SETTER = "set"; /** Constant meaning accessor type getter. */ public static final String GETTER = "get"; /** Constant meaning accessor type getter for boolean. */ public static final String BOOLEAN_GETTER = "is"; /** * Instantiate a Class using its name. * @param className The class name. * @param arguments The arguments to be passed to constructor. * @param types The types of arguments. * @return The instance * @throws ClassNotFoundException Thrown if you try to instanciate a class that does not exist. * @throws NoSuchMethodException Thrown if you try to retreive a method that does not exist. * @throws InvocationTargetException Can occure during invocation * @throws IllegalAccessException Thrown while trying to access illagaly the instance * @throws InstantiationException Any other case */ public static Object newInstance(final String className, final Object[] arguments, final Class[] types) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException { // Retrieve class to be load Class clazz = Class.forName(className); // R??cup??ration du constructeur correspondant ????????? la liste des parametres donn??e Constructor constructor = clazz.getConstructor(types); // Cr??ation d'une instance avec le constructeur r??cup??r??s return constructor.newInstance(arguments); } /** * Instantiate a Class using its name. * @param className The class name. * @param arguments The parameters to be passed to constructor. * @return The instance * @throws ClassNotFoundException Thrown if you try to instanciate a class that does not exist. * @throws NoSuchMethodException Thrown if you try to retreive a method that does not exist. * @throws InvocationTargetException Can occure during invocation * @throws IllegalAccessException Thrown while trying to access illagaly the instance * @throws InstantiationException Any other case */ public static Object newInstance(final String className, final Object[] arguments) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException { // Construct the types array Class[] types = new Class[arguments.length]; for (int i = 0; i <= arguments.length; ++i) { types[i] = arguments[i].getClass(); } // Instantiate class return newInstance(className, arguments, types); } /** * Instantiate a Class using its name. * @param className The class name * @return The instance * @throws ClassNotFoundException Thrown if you try to instanciate a class that does not exist. * @throws InstantiationException Any other case * @throws NoSuchMethodException Thrown if you try to retreive a method that does not exist. * @throws InvocationTargetException Can occure during invocation * @throws IllegalAccessException Thrown while trying to access illagaly the instance */ public static Object newInstance(final String className) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException { return newInstance(className, new Object[] {}); } /** * Invoke a methods (<code>methodName</code>) from an <code>object</code> with <code>arguments</code> of <code>types</code>. * @param object The object from which you want to invoke a methods. * @param methodName The method name to invoke. * @param arguments The arguments to pass to the methods. * @param types The types of arguments. * @return the result of the invoked method. * @throws NoSuchMethodException Thrown if you try to retreive a method that does not exist. * @throws InvocationTargetException Can occure during invocation * @throws IllegalAccessException Thrown while trying to access illagaly the instance */ public static Object invokeMethod(final Object object, final String methodName, final Object[] arguments, final Class[] types) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException { try { // If simple getter is not found ... try boolean one return getMethod(object.getClass(), methodName, types).invoke(object, arguments); } catch (NoSuchMethodException ex) { NoSuchMethodException thrown = new NoSuchMethodException(formatInvokeGetterException(ex, object, methodName, arguments)); thrown.setStackTrace(ex.getStackTrace()); throw thrown; } catch (InvocationTargetException ex) { throw new InvocationTargetException(ex.getTargetException(), formatInvokeGetterException(ex.getTargetException(), object, methodName, arguments)); } catch (IllegalAccessException ex) { IllegalAccessException thrown = new IllegalAccessException(formatInvokeGetterException(ex, object, methodName, arguments)); thrown.setStackTrace(ex.getStackTrace()); throw thrown; } } /** * Invoke a methods (<code>methodName</code>) from an <code>object</code> with <code>arguments</code> of <code>types</code>. * @param object The object from which you want to invoke a methods. * @param method The method to invoke. * @param arguments The arguments to pass to the methods. * @return the result of the invoked method. * @throws InvocationTargetException Can occure during invocation * @throws IllegalAccessException Thrown while trying to access illagaly the instance */ public static Object invokeMethod(final Object object, final Method method, final Object[] arguments) throws IllegalAccessException, InvocationTargetException { return method.invoke(object, arguments); } /** * Invoke a methods (<code>methodName</code>) from an <code>object</code> with <code>arguments</code> of <code>types</code>. * @param clazz The <code>clazz</code> on which to retreive the method. * @param methodName The method name to invoke. * @param arguments The arguments to pass to the methods. * @param types The types of arguments. * @return the result of the invoked method. * @throws NoSuchMethodException Thrown if you try to retreive a method that does not exist. * @throws InvocationTargetException Can occure during invocation * @throws IllegalAccessException Thrown while trying to access illagaly the instance */ public static Object invokeStaticMethod(final Class clazz, final String methodName, final Object[] arguments, final Class[] types) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException { return getMethod(clazz, methodName, types).invoke(null, arguments); } /** * Invoke a methods (<code>methodName</code>) from an <code>object</code> with <code>arguments</code>. * @param object The object from which you want to invoke a methods. * @param methodName The method name to invoke. * @param arguments The arguments to pass to the methods. * @return the result of the invoked method. * @throws NoSuchMethodException Thrown if you try to retreive a method that does not exist. * @throws InvocationTargetException Can occure during invocation * @throws IllegalAccessException Thrown while trying to access illagaly the instance */ public static Object invokeMethod(final Object object, final String methodName, final Object[] arguments) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException { // Construct the types array Class[] types = new Class[arguments.length]; for (int i = 0; i < arguments.length; ++i) { types[i] = arguments[i].getClass(); } return invokeMethod(object, methodName, arguments, types); } /** * This method invoke the setter according to the <code>fieldName</code> on the <code>toFill</code> object with as argument. * <code>valueToSet</code> of type <code>valueToSetType</code> * @param toFill the object to fill. * @param fieldName the field name. * @param valueToSet the value to set. * @param valueToSetType the type of the value to set. * @throws NoSuchMethodException Thrown if you try to retreive a method that does not exist. * @throws InvocationTargetException Can occure during invocation * @throws IllegalAccessException Thrown while trying to access illagaly the instance */ public static void invokeSetter(final Object toFill, final String fieldName, final Object valueToSet, final Class valueToSetType) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException { invokeMethod(toFill, computeAccessorMethodName(SETTER, fieldName), new Object[] {valueToSet}, new Class[] {valueToSetType}); } /** * This method invoke the getter according to the <code>fieldName</code> on the <code>toFill</code> object with as argument. * <code>valueToSet</code> of type <code>valueToSetType</code> * @param bean the JavaBean object. * @param fieldName the field name. * @return The value returned by the getter. * @throws NoSuchMethodException Thrown if you try to retreive a method that does not exist. * @throws InvocationTargetException Can occure during invocation * @throws IllegalAccessException Thrown while trying to access illagaly the instance */ public static Object invokeGetter(final Object bean, final String fieldName) throws IllegalAccessException, NoSuchMethodException, InvocationTargetException { String field = fieldName; Object instance = bean; while (field.indexOf('[') > -1) { // Invoke getter to retreive the child element instance = invokeGetter(instance, field.substring(0, field.indexOf('['))); // If result is null no need to continue if (instance == null) { return null; } // Re route field name to retreive the field of the child instance int index = Integer.parseInt(field.substring(field.indexOf('[') + 1, field.indexOf(']'))); instance = Array.get(instance, index); field = field.substring(field.indexOf(']') + 1); } // In the case that you want to retrieve in one time the field of a child object while (field.indexOf('.') > 0) { // Invoke getter to retreive the child element instance = invokeGetter(instance, field.substring(0, field.indexOf('.'))); // If result is null no need to continue if (instance == null) { return null; } // Re route field name to retreive the field of the child instance field = field.substring(field.indexOf('.') + 1); } if (field.length() == 0) { return instance; } try { return invokeMethod(instance, computeAccessorMethodName(GETTER, field), new Object[] {}); } catch (NoSuchMethodException noSuchMethod) { String accessor = computeAccessorMethodName(BOOLEAN_GETTER, field); try { // If simple getter is not found ... try boolean one return invokeMethod(instance, accessor, new Object[] {}); } catch (NoSuchMethodException ex) { // If it's still not found or return an error ... than throw the original error. throw noSuchMethod; } } } /** * Format a more detailed message when an exception occured during invocation. * @param ex The exception * @param object The object on which the given method is invoked * @param method The invoked method * @param arguments The method arguments * @return The detailed message */ private static String formatInvokeGetterException(final Throwable ex, final Object object, final String method, final Object[] arguments) { String message = ex.getMessage(); if (message == null) { message = ""; } else { message += " - "; } String args = ""; for (int i = 0; i < arguments.length; ++i) { args += arguments[i].getClass().getName(); // Concat each element args += arguments[i]; // Add separator if necessary if ((i < arguments.length - 1)) { args += ", "; } } return message + "Error occured while tyring to invoke " + object.getClass().getName() + "." + method + "(" + args + ") method."; } /** * Get the field (<code>filedName</code>) value of an <code>object</code>. * @param object The <code>object</code> on which to retreive the field value. * @param fieldName The <code>fieldName</code> to retreive. * @return The value of the field. * @throws NoSuchFieldException Thrown if you try to retreive a field that does not exist. * @throws InvocationTargetException Can occure during invocation * @throws IllegalAccessException Thrown while trying to access illagaly the instance */ public static Object getFieldValue(final Object object, final String fieldName) throws NoSuchFieldException, IllegalAccessException, InvocationTargetException { try { return getField(object.getClass(), fieldName).get(object); } catch (NoSuchFieldException ex) { try { return invokeGetter(object, fieldName); } catch (NoSuchMethodException x) { throw ex; } } } /** * Get the field (<code>filedName</code>) of a class (<code>clazz</code>). * @param clazz The <code>clazz</code> on which to retreive the field. * @param fieldName The <code>fieldName</code> to retreive. * @return The Field object of the given class. * @throws NoSuchFieldException Thrown if you try to retreive a field that does not exist. */ public static Field getField(final Class clazz, final String fieldName) throws NoSuchFieldException { try { Field f = clazz.getDeclaredField(fieldName); f.setAccessible(true); return f; } catch (SecurityException e) { throw new RuntimeException(e); } catch (NoSuchFieldException e) { if (clazz == Object.class) { throw e; } // Get the one from parent super class recursivly return getField(clazz.getSuperclass(), fieldName); } } /** * Return all declared fields of a class (and all its super class). * @see {@link Class#getDeclaredFields()} * @param clazz The class on which to retreive the fields. * @return All the fields. */ public static List getDeclaredFields(final Class clazz) { List fields = new ArrayList(); Class current = clazz; while (!current.getName().equals(Object.class.getName())) { fields.addAll(Arrays.asList(current.getDeclaredFields())); current = current.getSuperclass(); } return fields; } /** * Return all getter of a class (but not the ones from parent). * @param clazz The class on which to retreive the getters. * @return All the methods. */ public static List getGetters(final Class clazz) { List getters = new ArrayList(); if (clazz != null) { Method[] methods = clazz.getMethods(); for (int i = 0; i < methods.length; i++) { if (methods[i].getDeclaringClass().equals(clazz)) { if ((methods[i].getName().startsWith(GETTER) || methods[i].getName().startsWith(BOOLEAN_GETTER)) && methods[i].getParameterTypes().length == 0) { getters.add(methods[i]); } } } } return getters; } /** * Return all getter of a class (even parent's ones). * @param clazz The class on which to retreive the getters. * @return All the methods. */ public static List getGettersRecursivly(final Class clazz) { List getters = new ArrayList(); if (clazz != null) { Class current = clazz; while (!current.getName().equals(Object.class.getName())) { Method[] methods = current.getMethods(); for (int i = 0; i < methods.length; i++) { if (methods[i].getDeclaringClass().equals(current)) { if ((methods[i].getName().startsWith(GETTER) || methods[i].getName().startsWith(BOOLEAN_GETTER)) && methods[i].getParameterTypes().length == 0) { getters.add(methods[i]); } } } current = current.getSuperclass(); } } return getters; } /** * Return all getter of a class (but not the ones from parent). * @param clazz The class on which to retreive the getters. * @return All the methods. */ public static List getSetters(final Class clazz) { List getters = new ArrayList(); if (clazz != null) { Method[] methods = clazz.getMethods(); for (int i = 0; i < methods.length; i++) { if (methods[i].getDeclaringClass().equals(clazz)) { if (methods[i].getName().startsWith(SETTER) && methods[i].getName().length() > SETTER.length() && methods[i].getParameterTypes().length == 1) { getters.add(methods[i]); } } } } return getters; } /** * Return all getter of a class (even parent's ones). * @param clazz The class on which to retreive the getters. * @return All the methods. */ public static List getSettersRecursivly(final Class clazz) { List getters = new ArrayList(); if (clazz != null) { Class current = clazz; while (!current.getName().equals(Object.class.getName())) { Method[] methods = current.getMethods(); for (int i = 0; i < methods.length; i++) { if (methods[i].getDeclaringClass().equals(current)) { if (methods[i].getName().startsWith(SETTER) && methods[i].getName().length() > SETTER.length() && methods[i].getParameterTypes().length == 1) { getters.add(methods[i]); } } } current = current.getSuperclass(); } } return getters; } /** * Retreive the method (<code>methodName</code>) of a class (<code>clazz</code>) using parameters <code>types</code>. * @param clazz The <code>clazz</code> on which to retreive the method. * @param methodName The method name to retreive. * @param types The types of the method's arguments. * @return A Method objec. * @throws NoSuchMethodException Thrown if you try to retreive a method that does not exist. */ public static Method getMethod(final Class clazz, final String methodName, final Class[] types) throws NoSuchMethodException { try { Method m = clazz.getDeclaredMethod(methodName, types); m.setAccessible(true); return m; } catch (NoSuchMethodException x) { try { if (clazz == Object.class) { throw x; } return getMethod(clazz.getSuperclass(), methodName, types); } catch (Exception ex) { throw x; } } } /** * This method compute the accessor method name according to the <code>accessorType</code> and <code>fieldName</code>. * @param accessorType the accessor type. * @param fieldName the field name. * @return the accessor method name. * @throw IllegalArgumentException If the arguments type is not valid. */ private static String computeAccessorMethodName(final String accessorType, final String fieldName) { if (!accessorType.equals(SETTER) && !accessorType.equals(GETTER) && !accessorType.equals(BOOLEAN_GETTER)) { throw new IllegalArgumentException("Accessor Type : " + accessorType + " isn't correct"); } if (null == fieldName || "".equals(fieldName)) { throw new IllegalArgumentException("fieldName migth not be null or empty"); } return accessorType + fieldName.replaceFirst("" + fieldName.charAt(0), ("" + fieldName.charAt(0)).toUpperCase()); } /** * If you want to map a getter/setter with its fied name. * Use this method to convert getter or setter into fieldname * @param method The method to be converted * @return The field name or method name if the method is neither a getter neither a setter */ public static String getFieldName(final Method method) { String prefix = null; if (method.getName().startsWith(GETTER)) { prefix = GETTER; } else if (method.getName().startsWith(SETTER)) { prefix = SETTER; } else if (method.getName().startsWith(BOOLEAN_GETTER)) { prefix = BOOLEAN_GETTER; } else { return method.getName(); } if (method.getName().length() == prefix.length()) { return method.getName(); } return ("" + method.getName().charAt(prefix.length())).toLowerCase() + method.getName().substring(prefix.length() + 1); } }