package Sequenic.T2.Engines; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import Sequenic.T2.T2annotation; /** * Utility class providing reflection functions to obtain constructors, * methods etc. */ public class Util { /** * Return true is C is a proper subclass of D (so it returns false if * C and D are the same class). */ static public boolean isProperSubclass(Class C, Class D) { return D.isAssignableFrom(C) && C!=D ; } /** * True if C and D belong to the same package. */ static public boolean isOfTheSamePackage(Class C, Class D) { return C.getPackage() == D.getPackage() ; } /** * Return true if member is an inherited member for the class C. */ static public boolean isInheritedMember(Object member, Class C) { int mod ; Class D ; //boolean isStaticMethod = false ; if (member instanceof Constructor) { Constructor cons = (Constructor) member ; mod = cons.getModifiers() ; D = cons.getDeclaringClass() ; } else if (member instanceof Field) { Field f = (Field) member ; mod = f.getModifiers() ; D = f.getDeclaringClass() ; } else if (member instanceof Method) { Method m = (Method) member ; mod = m.getModifiers() ; D = m.getDeclaringClass() ; //isStaticMethod = Modifier.isStatic(mod) ; } else return false ; if (! isProperSubclass(C,D)) return false ; //if (isStaticMethod) return false ; if (isOfTheSamePackage(C,D)) return ! Modifier.isPrivate(mod) ; else return Modifier.isPublic(mod) || Modifier.isProtected(mod) ; } /** * This method returns true if f is an inherited but hidden field to C. * This is the case if C declares its own field with the same name. */ static public boolean isHiddenField(Field f, Class C) { if (! isInheritedMember(f,C)) return false ; try { C.getDeclaredField(f.getName()) ; // Ok, so a field of the same name exists in C: return true ; } catch (Exception e) { return false ; } } /** * This method returns true if m is an inherited but hidden method to C. * This is the case if m is static and C declares its own m with the * same signature. */ static public boolean isHiddenMethod(Method m, Class C) { if (! isInheritedMember(m,C)) return false ; try { Class[] paramTypes = m.getParameterTypes() ; C.getDeclaredMethod(m.getName(), paramTypes) ; // Then a method of the same signature exists in C; // m is hidden only if it is static: return Modifier.isStatic(m.getModifiers()) ; } catch (Exception e) { return false ; } } /** * This method returns true if m is an inherited but overriden method to C. * This is the case if m is non-static and C declares its own m with the * same signature. */ static public boolean isOverRidenMethod(Method m, Class C) { if (! isInheritedMember(m,C)) return false ; Class D = m.getDeclaringClass() ; try { Class[] paramTypes = m.getParameterTypes() ; C.getDeclaredMethod(m.getName(), paramTypes) ; // Then a method of the same signature exists in C; // m is overriden only if it is not static: return ! Modifier.isStatic(m.getModifiers()) ; } catch (Exception e) { return false ; } } /** * Get all (incl. private) declared constructors of the given target class; * they form the maximum testing scope for constructors. */ public static List getAllCons(Class C) { List result = new LinkedList(); Constructor[] cons = C.getDeclaredConstructors(); for (int i = 0; i < cons.length; i++) { // cons[i].setAccessible(true) ; if (cons[i].getAnnotation(T2annotation.exclude.class) == null) result.add(cons[i]); } return result; } /** * Get the public constructors of a given class. Has nothing to do * with testing scope. */ public static List getPubCons(Class C) { List result = new LinkedList(); Constructor[] cons = C.getDeclaredConstructors(); for (int i = 0; i < cons.length; i++) { if (Modifier.isPublic(cons[i].getModifiers())) { result.add(cons[i]); } } return result; } /** * To obtain all non-interface and non-abstract superclasses of a given * class. The class "Object" is not included in the returned list. */ public static List getAllSuperClasses(Class C) { List collected = new LinkedList(); if (C.isInterface() || Modifier.isAbstract(C.getModifiers()) || C.getName().equals("java.lang.Object")) { return collected; } collected.add(C); collected.addAll(getAllSuperClasses(C.getSuperclass())); return collected; } static public boolean isMainMethod(Method m) { if (!m.getName().equals("main")) return false ; Class[] paramTypes = m.getParameterTypes() ; if (paramTypes==null || paramTypes.length!=1) return false ; Class param0Type = paramTypes[0] ; return param0Type.isArray() && param0Type.getComponentType() == String.class ; } /** * Get 'all' methods of a class. This delivers the maximum testing * scope for methods. This includes, in principle, inherited methods. * Abstract, hidden, and overloaded methods are not included! * Methods marked as specifications are not included as well. */ public static List getAllMeths(Class C) { Class CLASS_OBJECT = Object.class; List methods = new LinkedList(); List ancestors = getAllSuperClasses(C); //System.out.println(">> #ancestors: " + ancestors.size()) ; Method[] ms = null; Method m ; String name ; int i = 0; for (Class D : ancestors) { ms = D.getDeclaredMethods(); for (i = 0; i < ms.length; i++) { m = ms[i] ; name = m.getName(); if (((D==C) || (isInheritedMember(m,C) && !isHiddenMethod(m,C) && !isOverRidenMethod(m,C))) && !Modifier.isAbstract(m.getModifiers()) && (m.getDeclaringClass() != CLASS_OBJECT) && ! name.equals(BaseEngine.CLASSINV_STR) && ! name.endsWith(BaseEngine.SPEC_STR) // exclude main for now ... && !isMainMethod(m) && m.getAnnotation(T2annotation.exclude.class) == null ) methods.add(m); } } return methods ; } /** * This delivers all the fields that are in the maximum testting scope. * This includes in principle inherited fields. However, abstract, hidden, * final, and static fields are excluded. Fields marked as auxilliary variables * are also excluded. */ public static List getAllFields(Class C) { // First get all fields: List fields = new LinkedList(); List ancestors = getAllSuperClasses(C); Field[] fs = null; Field f ; int modifier ; int i = 0; for (Class D : ancestors) { fs = D.getDeclaredFields(); for (i = 0; i < fs.length; i++) { f = fs[i] ; modifier = f.getModifiers() ; if (((D==C) || (isInheritedMember(f,C) && !isHiddenField(f,C))) && !Modifier.isAbstract(modifier) && !Modifier.isStatic(modifier) && !Modifier.isFinal(modifier) && ! f.getName().startsWith(BaseEngine.AUX_STR) && f.getAnnotation(T2annotation.exclude.class) == null ) fields.add(fs[i]); } } return fields ; } /** * Filter a given list of constructors. It returns a list of constructors * satisfying the given access option. */ public static List filterCons(AccessOption filter, List constructors) { List result = new LinkedList(); for (Constructor c : constructors) { if (filter.isAllowed(c.getDeclaringClass(), c.getModifiers())) { result.add(c); } } return result; } /** * Filter a given list of methods. It returns a list of methods * satisfying the given access option. */ public static List filterMethods(AccessOption filter, List methods) { List result = new LinkedList(); for (Method m : methods) { // System.out.println(">>" + m.getName() + "-->" + Modifier.isProtected(m.getModifiers())) ; if (filter.isAllowed(m.getDeclaringClass(), m.getModifiers())) { result.add(m); // System.out.println("## " + m.getName()) ; } } return result; } static private boolean nameMatch(String s, List names) { boolean match = false; for (String name : names) { if (name.equals(s)) { match = true; break; } } return match; } /** * Filter a given list of methods. It returns a list of methods * whose name occur in the given list of names. */ public static List getMethodsByNames(List names, List methods) { List result = new LinkedList(); for (Method m : methods) { if (nameMatch(m.getName(), names)) { result.add(m); } } return result; } /** * Filter a given list of methods. It returns a list of methods * whose name does NOT occur in the given list of names. */ public static List excludeMethodsByNames(List names, List methods) { List result = new LinkedList(); for (Method m : methods) { if (!nameMatch(m.getName(), names)) { result.add(m); } } return result; } /** * Get the indices of the parameters of a method m that can accept * an object of class C. */ public static List canAcceptAsParameter(Class C, Method m) { Class[] paramTypes = m.getParameterTypes(); List result = new LinkedList() ; for (int i=0; i < paramTypes.length; i++) { if (paramTypes[i].isAssignableFrom(C) && paramTypes[i] != Object.class) result.add(i) ; } return result ; } /** * Return the list of methods that can accept CUT as a parameter (including * as the receiver object). */ public static List getMethodsCanAcceptCUTinParam(Class CUT, List methods) { List result = new LinkedList(); for (Method m : methods) { if (! canAcceptAsParameter(CUT,m).isEmpty()) { result.add(m); } } return result; } /** * Return the list of methods that can accept CUT as the receiver object. */ public static List getMethodsCanAcceptCUTinRec(Class CUT, List methods) { List result = new LinkedList(); for (Method m : methods) { if (!Modifier.isStatic(m.getModifiers())) { result.add(m); } } return result; } /** * Filter a given list of fields. It returns a list of fields * satisfying the given access option. */ public static List filterFields(AccessOption filter, List fields) { List result = new LinkedList(); if (filter.excludeField) { return result; } for (Field f : fields) { if (filter.isAllowed(f.getDeclaringClass(), f.getModifiers())) { result.add(f); } } return result; } /** * Filter a given list of fields. It returns a list of fields * whose name occur in the given list of names. */ public static List getFieldsByNames(List names, List fields) { List result = new LinkedList(); for (Field f : fields) { if (nameMatch(f.getName(), names)) { result.add(f); } } return result; } /** * Filter a given list of fields. It returns a list of fields * whose name does NOT occur in the given list of names. */ public static List excludeFieldsByNames(List names, List fields) { List result = new LinkedList(); for (Field f : fields) { if (!nameMatch(f.getName(), names)) { result.add(f); } } return result; } /** * Construct a mapping such that for any method m of the class C * that has m_spec as its specification, we add the pair * (m,m_spec) to the mapping. The method will also open access to * m_spec. */ public static HashMap mk_specMap(List methods) { HashMap map = new HashMap(); for (Method m : methods) { Method spec = null; Class[] paramTypes = m.getParameterTypes(); Class C = m.getDeclaringClass(); try { spec = C.getDeclaredMethod(m.getName() + BaseEngine.SPEC_STR, paramTypes); // spec.setAccessible(true) ; } catch (Exception e) { continue; } //System.out.println("## " + m.getName() + " | " + spec.getName()) ; if (Modifier.isStatic(m.getModifiers()) != Modifier.isStatic(spec.getModifiers())) { continue; } map.put(m, spec); } return map; } /** * Get the class-invariant of a class. */ static public Method getClassINV(Class C) { Method classINV = null; try { classINV = C.getDeclaredMethod(BaseEngine.CLASSINV_STR, (Class[]) null); if (classINV.getReturnType() != Boolean.TYPE) { return null; } if (Modifier.isStatic(classINV.getModifiers())) { return null; } } catch (Exception e) { } return classINV; } /** * Get the class invariant of a class and all its superclasses. * The class Object is excluded. */ static public List getSuperClassINVs(Class C) { List classes = getAllSuperClasses(C); LinkedList classinvs = new LinkedList(); Method inv = null; for (Class D : classes) { inv = getClassINV(D); //System.out.println(">> classinv: " + D.getName()) ; if (inv != null) { classinvs.add(inv); } } return classinvs; } /** * Return the 'Class' of the given name. */ public static Class classOf(String cname) throws ClassNotFoundException { if (cname.equals("boolean")) { return Boolean.TYPE; } if (cname.equals("byte")) { return Byte.TYPE; } if (cname.equals("int")) { return Integer.TYPE; } if (cname.equals("long")) { return Long.TYPE; } if (cname.equals("char")) { return Character.TYPE; } if (cname.equals("float")) { return Float.TYPE; } if (cname.equals("double")) { return Double.TYPE; } return Class.forName(cname); } /** * To get a constructor from a class. Unlike the stadard "getConstructor" from Class, * this one can get private constructor etc. The pre-condition here is that the * requested constructor does exists in C. */ public static Constructor getConstructor(Class C, Class[] params) throws NoSuchMethodException, SecurityException { if (C == null) { return null; } return C.getDeclaredConstructor(params); } /** * To get a field from a class. Unlike the stadard "getField" from Class, * this one can get private method etc. The pre-condition here is that the * requested field does exists in C, or its superclass. */ public static Field getField(Class C, String fname) { if (C == null) { return null; } Field f = null; try { f = C.getDeclaredField(fname); } catch (NoSuchFieldException e) { f = getField(C.getSuperclass(), fname); } return f; } /** Like Util.getField, but never returns null. * * @param C * @param fname * @return * @throws NoSuchFieldException */ public static Field getFieldNoNull(Class C, String fname) throws NoSuchFieldException { try { return C.getDeclaredField(fname); } catch (NoSuchFieldException e) { C = C.getSuperclass(); if(C!=null) return getFieldNoNull(C,fname); else throw e; } } /** * To get a method from a class. Unlike the stadard "getMethod" from Class, * this one can get private method etc. The pre-condition here is that the * requested method does exists in C, or its superclass. */ public static Method getMethod(Class C, String mname, Class[] params) { if (C == null) { return null; } Method m = null; try { m = C.getDeclaredMethod(mname, params); } catch (NoSuchMethodException e) { m = getMethod(C.getSuperclass(), mname, params); } return m; } public static Method getMethodNoNull(Class C, String mname, Class[] params) throws NoSuchMethodException { try { return C.getDeclaredMethod(mname, params); } catch (NoSuchMethodException e) { C = C.getSuperclass(); if(C!=null) return getMethodNoNull(C, mname, params); else throw e; } } /** * Make an instance of the class C whose name is given. The assumption * is that C has a constructor of signature C(). Just returns null is * it fails to do it. */ public static Object mkAnInstance(String cname) { try { Class C = Class.forName(cname); Class[] paramTypes = new Class[0]; Constructor con = C.getConstructor(paramTypes); Object[] params = new Object[0]; Object result = con.newInstance(params); return result; } catch (Exception e) { return null; } } }