package vooga.rts.util; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * This is a class that makes it much easier to do reflection. * It has a few methods that return the information that is needed. * * @author Jonathan Schmidt * @modified Francesco Agosti */ public class ReflectionHelper { /** * Finds the Constructor of a specified class that take in the * provided parameters. * * @param c The Class to search * @param params The parameters to find a constructor for * @return The constructor required to instantiate. * @throws ClassDefinitionException */ public static Constructor<?> findConstructor (Class<?> c, Object ... params) { Class<?>[] types = toClassArray(params); Constructor<?>[] constructors = c.getConstructors(); for (Constructor<?> con : constructors) { Class<?>[] conParams = con.getParameterTypes(); if (paramsEqual(types, conParams)) { return con; } } return null; } /** * Retuns a new instance of your class given your parameters. * @param Class object * @param Parameters of constructor * @return */ public static Object makeInstance(Class<?> c, Object ... params){ try { return findConstructor(c,params).newInstance(params); } catch (Exception e) { e.printStackTrace(); } return null; } /** * Returns a new instance of the class defined by your path and your parameters */ public static Object makeInstance(String path, Object ... params){ return makeInstance(makeClass(path), params); } /** * Returns the class object that is located at path. */ private static Class<?> makeClass(String path){ Class<?> thisClass = null; try { thisClass = Class.forName(path); } catch (ClassNotFoundException e) { e.printStackTrace(); } return thisClass; } /** * Finds and returns the requested method. * * @param c The class to search in. * @param methodName The name of the Method. * @param params The parameters that the method takes in. * @return * @throws NoSuchMethodException */ public static Method findMethod (Class<?> c, String methodName, Class<?>[] params) throws NoSuchMethodException { Method res = c.getMethod(methodName, params); return res; } /** * Finds and returns the requested method * * @param c The class to search in. * @param methodName The method name * @param params An array of objects that contain the parameters for the method. * @return The requested Method * @throws NoSuchMethodException */ public static Method findMethod (Class<?> c, String methodName, Object[] params) throws NoSuchMethodException { Class<?>[] types = toClassArray(params); return findMethod(c, methodName, types); } private static boolean paramsEqual (Class<?>[] c1, Class<?>[] c2) { if (c1.length != c2.length) { return false; } for (int i = 0; i < c1.length; i++) { boolean similar = c1[i].isAssignableFrom(c2[i]) || c2[i].isAssignableFrom(c1[i]); if (!similar) { return false; } } return true; } private static Class<?>[] toClassArray (Object ... params) { Class<?>[] types = new Class<?>[params.length]; for (int i = 0; i < params.length; i++) { types[i] = params[i].getClass(); // Override Primitive Types if (types[i] == Integer.class) { types[i] = int.class; } if (types[i] == Boolean.class) { types[i] = boolean.class; } if(types[i] == Double.class) { types[i] = double.class; } } return types; } private static Field getField (String property, Object object) { Class<?> curClass = object.getClass(); do { try { Field toSet = curClass.getDeclaredField(property); return toSet; } catch (NoSuchFieldException e) { curClass = curClass.getSuperclass(); } catch (SecurityException e) { curClass = null; } } while (curClass != null); return null; } private static boolean setValue (Field toSet, Object object, Object value) { boolean prevAccess = toSet.isAccessible(); toSet.setAccessible(true); try { toSet.set(object, value); return true; } catch (IllegalArgumentException e) { } catch (IllegalAccessException e) { } toSet.setAccessible(prevAccess); return false; } private static Object getValue (Field toSet, Object object) { Object value = null; boolean prevAccess = toSet.isAccessible(); toSet.setAccessible(true); try { value = toSet.get(object); } catch (IllegalArgumentException e) { } catch (IllegalAccessException e) { } toSet.setAccessible(prevAccess); return value; } /** * Sets the value of a field in an object using reflection. * Iterates through all the super classes to find a field that * matches. * * @param property The name of the property to set. * @param object The object that the property should be set on. * @param value The value to set the value to. * @return Whether it was able to set the value or not. */ public static <T> boolean setValue (String property, Object object, T value) { Field toSet = getField(property, object); return setValue(toSet, object, value); } /** * Changes the value of a property by a certain amount. This makes it easier to increase * or decrease values by a certain amount. <br /> * * Right now it supports only Integers and Doubles <br /> * It basically replaces setValue with a getValue and a modification. * * @param property The property to change * @param object The object to change the value of * @param value How much to change the value by. * @return Whether it was able to change the value. */ public static <T extends Number> boolean changeValue (String property, Object object, T value) { Field toSet = getField(property, object); Number val = (Number) getValue(toSet, object); if (value instanceof Integer) { Integer intVal = val.intValue(); intVal += (Integer) value; val = intVal; } if (value instanceof Double) { Double dVal = val.doubleValue(); dVal += (Double) dVal; val = dVal; } return setValue(toSet, object, val); } /** * Returns the value of a property of a specific Object. * * @param property The property name to get. * @param object The object to get the value from. * @return The value of the property. */ public static <T> T getValue (String property, Object object) { Field toSet = getField(property, object); try { @SuppressWarnings("unchecked") T result = (T) getValue(toSet, object); return result; } catch (Exception e) { return null; } } }