00001
00005 package edu.mit.csail.sdg.squander.utils;
00006
00007 import java.lang.annotation.Annotation;
00008 import java.lang.reflect.Array;
00009 import java.lang.reflect.Constructor;
00010 import java.lang.reflect.Field;
00011 import java.lang.reflect.InvocationTargetException;
00012 import java.lang.reflect.Method;
00013 import java.lang.reflect.Modifier;
00014 import java.lang.reflect.Type;
00015 import java.util.ArrayList;
00016 import java.util.Arrays;
00017 import java.util.Collection;
00018 import java.util.HashMap;
00019 import java.util.LinkedList;
00020 import java.util.List;
00021 import java.util.Map;
00022
00023 import kodkod.util.collections.IdentityHashSet;
00024
00029 public class ReflectionUtils {
00030
00031 static Map<Class<?>, Map<String, Field>> cache = new HashMap<Class<?>, Map<String, Field>>();
00032
00033 public static Field getFieldWithAccess(Object obj, String fieldName) {
00034 return getFieldWithAccess(obj.getClass(), fieldName);
00035 }
00036
00037 public static Field getFieldWithAccess(Class<?> cls, String fieldName) {
00038 Field f = getField(cls, fieldName);
00039 f.setAccessible(true);
00040 return f;
00041 }
00042
00051 public static Field getField(Class<?> cls, String fieldName) {
00052 Field f = null;
00053 Map<String, Field> inner = cache.get(cls);
00054 if (inner != null) {
00055 f = inner.get(fieldName);
00056 if (f != null)
00057 return f;
00058 } else {
00059 inner = new HashMap<String, Field>();
00060 cache.put(cls, inner);
00061 }
00062
00063 try {
00064 while (cls != null) {
00065 try {
00066 f = cls.getDeclaredField(fieldName);
00067 f.setAccessible(true);
00068 } catch (NoSuchFieldException e) {
00069 f = null;
00070 }
00071 if (f != null)
00072 break;
00073 cls = cls.getSuperclass();
00074 }
00075
00076 } catch (SecurityException e) {
00077 throw new RuntimeException("SecurityException", e);
00078 }
00079 if (f != null) {
00080 inner.put(fieldName, f);
00081 }
00082 return f;
00083 }
00084
00085 @SuppressWarnings("unchecked")
00086 public static <R> R getFieldValue(Object obj, Field field) {
00087 try {
00088 boolean accesible = field.isAccessible();
00089 field.setAccessible(true);
00090 Object ret = field.get(obj);
00091 field.setAccessible(accesible);
00092 return (R) ret;
00093 } catch (IllegalArgumentException e) {
00094 e.printStackTrace();
00095 } catch (IllegalAccessException e) {
00096 e.printStackTrace();
00097 }
00098 return null;
00099 }
00100
00101 @SuppressWarnings("unchecked")
00102 public static <R> R getFieldValue(Object obj, String fieldName) {
00103 return (R) getFieldValue(obj, getField(obj.getClass(), fieldName));
00104 }
00105
00106 public static void setFieldValue(Object obj, String field, Object value) {
00107 setFieldValue(obj, getField(obj.getClass(), field), value);
00108 }
00109
00110 public static void setFieldValue(Object obj, Field field, Object value) {
00111 try {
00112 boolean accessible = field.isAccessible();
00113 field.setAccessible(true);
00114 field.set(obj, value);
00115 field.setAccessible(accessible);
00116 } catch (IllegalArgumentException e) {
00117 throw new RuntimeException("IllegalArgumentException", e);
00118 } catch (IllegalAccessException e) {
00119 throw new RuntimeException("IllegalAccessExceptione", e);
00120 }
00121 }
00122
00123 private static void getAllFieldsRecursive(Class<?> clz, List<Field> fldLst) {
00124 if (clz == null)
00125 return;
00126 if (clz.isPrimitive())
00127 return;
00128 for (Field f : clz.getDeclaredFields()) {
00129 f.setAccessible(true);
00130 fldLst.add(f);
00131 }
00132 if (clz.getSuperclass() == Object.class)
00133 return;
00134 else
00135 getAllFieldsRecursive(clz.getSuperclass(), fldLst);
00136 }
00137
00138 public static Field[] getAllFields(Class<?> clz) {
00139 ArrayList<Field> fieldList = new ArrayList<Field>();
00140 getAllFieldsRecursive(clz, fieldList);
00141 if (fieldList.isEmpty())
00142 return new Field[0];
00143 else
00144 return fieldList.toArray(new Field[0]);
00145 }
00146
00147 public static Field[] getAllNonStaticFields(Class<?> clz) {
00148 List<Field> fList = new ArrayList<Field>();
00149 getAllFieldsRecursive(clz, fList);
00150 List<Field> nonStaticFields = new LinkedList<Field>();
00151 for (Field f : fList) {
00152 if ((f.getModifiers() & Modifier.STATIC) == 0) {
00153 nonStaticFields.add(f);
00154 }
00155 }
00156 if (nonStaticFields.isEmpty())
00157 return new Field[0];
00158 else
00159 return nonStaticFields.toArray(new Field[0]);
00160 }
00161
00162 public static Field[] getDeclaredNonStaticFields(Class<?> clz) {
00163 List<Field> nonStaticFields = new LinkedList<Field>();
00164 for (Field f : clz.getDeclaredFields()) {
00165 if (!Modifier.isStatic(f.getModifiers())) {
00166 f.setAccessible(true);
00167 nonStaticFields.add(f);
00168 }
00169 }
00170 if (nonStaticFields.isEmpty())
00171 return new Field[0];
00172 else
00173 return nonStaticFields.toArray(new Field[0]);
00174 }
00175
00186 public static Method getMethod(Class<? extends Object> clz,
00187 String methodName, Class<?>[] methodArgs) throws NoSuchMethodException {
00188 if (clz == null)
00189 throw new NoSuchMethodException(methodName + "(" + methodArgs + ") method does not exist ");
00190 try {
00191 return clz.getDeclaredMethod(methodName, methodArgs);
00192 } catch (NoSuchMethodException e) {
00193 return getMethod(clz.getSuperclass(), methodName, methodArgs);
00194 }
00195 }
00196
00197 public static Method findMethod(Class<?> clz, String methodName, Class<?>[] methodParams) throws NoSuchMethodException {
00198 Method methodFound = null;
00199 l: for (Method m : clz.getDeclaredMethods()) {
00200 if (!m.getName().equals(methodName))
00201 continue;
00202 if (m.getParameterTypes().length != methodParams.length)
00203 continue;
00204 for (int i = 0; i < m.getParameterTypes().length; i++)
00205 if (!paramsMatch(m.getParameterTypes()[i], methodParams[i]))
00206 continue l;
00207 if (methodFound != null)
00208 throw new RuntimeException("Multiple possibilities");
00209 methodFound = m;
00210 }
00211 if (methodFound != null)
00212 return methodFound;
00213 if (clz.getSuperclass() != null)
00214 return findMethod(clz.getSuperclass(), methodName, methodParams);
00215 else
00216 throw new NoSuchMethodException(methodName + " (" + Arrays.toString(methodParams) + ") not found in " + clz.getName());
00217 }
00218
00219 private static boolean paramsMatch(Class<?> declared, Class<?> actual) {
00220 declared = box(declared);
00221 actual = box(actual);
00222 return declared.isAssignableFrom(actual);
00223 }
00224
00225 public static Class<?> box(Class<?> c) {
00226 if (c == int.class)
00227 return Integer.class;
00228 if (c == boolean.class)
00229 return Boolean.class;
00230 if (c == float.class)
00231 return Float.class;
00232 if (c == double.class)
00233 return Double.class;
00234 if (c == long.class)
00235 return Long.class;
00236 if (c == byte.class)
00237 return Byte.class;
00238 if (c == char.class)
00239 return Character.class;
00240 return c;
00241 }
00242
00255 public static Object invoke(Object obj, String method, Class<?>[] params, Object[] args) {
00256 try {
00257 return invoke_ex(obj, method, params, args);
00258 } catch (Exception e) {
00259 throw new RuntimeException(e);
00260 }
00261 }
00262
00263 public static Object invoke_ex(Object obj, String method, Class<?>[] params, Object[] args)
00264 throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
00265 Class<?> clazz = null;
00266 if (obj instanceof Class<?>) {
00267 clazz = (Class<?>) obj;
00268 } else {
00269 clazz = obj.getClass();
00270 }
00271 Method methods = clazz.getDeclaredMethod(method, params);
00272 methods.setAccessible(true);
00273 if (obj instanceof Class<?>) {
00274 return methods.invoke(null, args);
00275 } else {
00276 return methods.invoke(obj, args);
00277 }
00278 }
00279
00288 public static Object createObjectDefaultConstructor(Class<?> clz) {
00289 try {
00290 Constructor<?> constr = clz.getDeclaredConstructor(new Class<?>[0]);
00291 constr.setAccessible(true);
00292 Object ret = constr.newInstance(new Object[0]);
00293 constr.setAccessible(false);
00294 return ret;
00295 } catch (Exception e) {
00296 throw new RuntimeException("could not create on object of class " + clz.getName() +
00297 " using default constructor. Reason: " + e.getMessage());
00298 }
00299 }
00300
00301 public static Object createNewArray(Class<?> componentType, int len) {
00302 return Array.newInstance(componentType, len);
00303 }
00304
00305 public static <T, K> T newInstance(Class<T> clz, Class<K> argType, K arg) {
00306 try {
00307 Constructor<T> cnstr = clz.getDeclaredConstructor(argType);
00308 cnstr.setAccessible(true);
00309 return cnstr.newInstance(arg);
00310 } catch (Exception e) {
00311 throw new RuntimeException(e);
00312 }
00313 }
00314
00315 public static <T> T newInstance(Class<T> clz, Object[] args) {
00316 Class<?>[] argTypes = new Class<?>[args.length];
00317 for (int i = 0; i < args.length; i++)
00318 argTypes[i] = args.getClass();
00319 return newInstance(clz, argTypes, args);
00320 }
00321
00322 public static <T> T newInstance(Class<T> clz, Class<?>[] argTypes, Object[] args) {
00323 try {
00324 Constructor<T> cnstr = clz.getDeclaredConstructor(argTypes);
00325 cnstr.setAccessible(true);
00326 return cnstr.newInstance(args);
00327 } catch (Exception e) {
00328 throw new RuntimeException(e);
00329 }
00330 }
00331
00332 public static <T, K, V> T newInstance(Class<T> clz, Class<K> arg1Type, Class<V> arg2Type, K arg1, V arg2) {
00333 try {
00334 Constructor<T> cnstr = clz.getDeclaredConstructor(arg1Type, arg2Type);
00335 cnstr.setAccessible(true);
00336 return cnstr.newInstance(arg1, arg2);
00337 } catch (Exception e) {
00338 throw new RuntimeException(e);
00339 }
00340 }
00341
00354 public static Method getAnnotatedMethod(Class<?> owner, Class<? extends Annotation> annotation) {
00355 Method[] methods = owner.getDeclaredMethods();
00356 Method ret = null;
00357 for (Method m : methods) {
00358 if (m.getAnnotation(annotation) != null)
00359 if (ret == null)
00360 ret = m;
00361 else
00362 throw new RuntimeException(
00363 "There are multiple methods to check");
00364 }
00365 return ret;
00366 }
00367
00368 public static Method [] getAnnotatedMethods(Class<?> owner, Class<? extends Annotation> annotation) {
00369 Method[] methods = owner.getDeclaredMethods();
00370 List<Method> ret = new LinkedList<Method>();
00371 for (Method m : methods) {
00372 if (m.getAnnotation(annotation) != null)
00373 ret.add(m);
00374 }
00375 return ret.toArray(new Method[0]);
00376
00377 }
00378
00379 public static boolean isPrimitive(Class<?> type) {
00380 if (type == null) return false;
00381 if (type.isPrimitive()) return true;
00382 if (Integer.class.equals(type) || Boolean.class.equals(type) || Byte.class.equals(type) || Character.class.equals(type) ||
00383 Double.class.equals(type) || Float.class.equals(type) || Long.class.equals(type) || Short.class.equals(type))
00384 return true;
00385 return false;
00386 }
00387
00391 @SuppressWarnings("unchecked")
00392 public static Class lca(Class clz1, Class clz2) {
00393 if (clz1.isAssignableFrom(clz2))
00394 return clz1;
00395 if (clz2.isAssignableFrom(clz1))
00396 return clz2;
00397 List<Class> workList = new LinkedList<Class>();
00398 workList.add(clz1);
00399 while (!workList.isEmpty()) {
00400 Class clz = workList.remove(0);
00401 if (clz2.isAssignableFrom(clz))
00402 return clz2;
00403 Class superClz = clz.getSuperclass();
00404 if (superClz != null)
00405 workList.add(superClz);
00406 for (Class intfce : clz.getInterfaces())
00407 workList.add(intfce);
00408 }
00409 return Object.class;
00410 }
00411
00415 public static String sig(Method method) {
00416 StringBuilder sig = new StringBuilder();
00417 sig.append(method.getDeclaringClass().getName()).append("::").append(method.getName());
00418 sig.append("(");
00419 for (Class<?> cls : method.getParameterTypes())
00420 sig.append(cls.getName()).append(",");
00421 sig.replace(sig.length() - 1, sig.length() - 1, ")");
00422 return sig.toString();
00423 }
00424
00425 public static Collection<Class<?>> getImmParents(Class<?> clz) {
00426 List<Class<?>> parents = new ArrayList<Class<?>>();
00427 if (clz.getSuperclass() != null)
00428 parents.add(clz.getSuperclass());
00429 for (Class<?> intr : clz.getInterfaces())
00430 parents.add(intr);
00431 return parents;
00432 }
00433
00434 public static Collection<Type> getImmGenericParents(Class<?> cls) {
00435 List<Type> supers = new ArrayList<Type>();
00436 if (cls.getGenericSuperclass() != null)
00437 supers.add(cls.getGenericSuperclass());
00438 for (Type t : cls.getGenericInterfaces())
00439 supers.add(t);
00440 return supers;
00441 }
00442
00443 private static final String tab = " ";
00444
00445 public static String toString(Object obj) {
00446 StringBuilder sb = new StringBuilder();
00447 String indent = "";
00448 printObj(obj, sb, indent, new IdentityHashSet<Object>());
00449 return sb.toString();
00450 }
00451
00452 private static void printObj(Object obj, StringBuilder sb, String indent, IdentityHashSet<Object> visited) {
00453 if (obj == null) {
00454 sb.append("null");
00455 return;
00456 }
00457 Class<? extends Object> cls = obj.getClass();
00458 if (cls == String.class || Utils.isPrimitive(cls)) {
00459 sb.append(obj.toString());
00460 return;
00461 }
00462 if (!visited.add(obj)) {
00463
00464 sb.append(obj.getClass().getName());
00465 return;
00466 }
00467
00468 sb.append(obj.getClass().getName());
00469 sb.append("\n");
00470 indent = indent + tab;
00471 for (Field f : getAllFields(cls)) {
00472 sb.append(indent).append(f.getName()).append(": ");
00473 printObj(getFieldValue(obj, f), sb, indent, visited);
00474 sb.append(";\n");
00475 }
00476 }
00477
00478 }