View Javadoc

1   package cz.cuni.amis.utils;
2   
3   import java.lang.ref.SoftReference;
4   import java.lang.reflect.Field;
5   import java.lang.reflect.Method;
6   import java.lang.reflect.Modifier;
7   import java.util.ArrayList;
8   import java.util.Collection;
9   import java.util.HashMap;
10  import java.util.LinkedHashSet;
11  import java.util.List;
12  import java.util.Map;
13  import java.util.Set;
14  
15  import cz.cuni.amis.utils.collections.MyCollections;
16  import cz.cuni.amis.utils.maps.HashMapMap;
17  
18  public class ClassUtils {
19  	
20  	/**
21  	 * Cache for results of 'getSubclasses' call.
22  	 */
23  	private static Map<Class, SoftReference<Set<Class>>> subclassesCache = 
24  		new HashMap<Class, SoftReference<Set<Class>>>();
25  	
26  	/**
27  	 * Adds 'interf' and all interfaces it extends into 'interfaces', called recursively.
28  	 * 
29  	 * @param interf
30  	 * @param interfaces
31  	 */
32  	@SuppressWarnings("unchecked")
33  	private static void probeInterface(Class interf, Set<Class> interfaces) {
34  		interfaces.add(interf);
35  		for (int i = 0; i < interf.getInterfaces().length; ++i) {
36  			probeInterface(interf.getInterfaces()[i], interfaces);
37  		}
38  	}
39  	
40  	/**
41  	 * Returns all interfaces and super-classes the class 'cls' implements / inherit including
42  	 * 'cls' itself.
43  	 * <p><p>
44  	 * <b>EXCEPT:</b>Object
45  	 * <p><p>
46  	 * Don't fear of the performance implications - the results are cached so
47  	 * every class is probed only once. 
48  	 * 
49  	 * @param cls
50  	 * @return
51  	 */
52  	@SuppressWarnings("unchecked")
53  	public static synchronized Collection<Class> getSubclasses(Class cls) {
54  		
55  		// get cached result
56  		SoftReference<Set<Class>> reference = subclassesCache.get(cls);
57  		
58  		Set<Class> classes = null;
59  		
60  		// do we have cached result?
61  		if (reference != null) {
62  			// probe the soft reference...
63  			classes = reference.get();			
64  		}
65  		
66  		// if classes are not null we've got cached result, return it...
67  		if (classes != null) return classes;		
68  		
69  		// if not ... probe the class
70  		classes = new LinkedHashSet<Class>();
71  		classes.add(cls);
72  		if (cls.getInterfaces() != null) {
73  			for (int i = 0; i < cls.getInterfaces().length; ++i) {
74  				probeInterface(cls.getInterfaces()[i], classes);				
75  			}
76  		}
77  		for (Class superClass = cls.getSuperclass(); superClass != null; superClass = superClass.getSuperclass()) {
78  			classes.add(superClass);
79  			if (superClass.getInterfaces() != null) {
80  				for (int i = 0; i < superClass.getInterfaces().length; ++i) {
81  					probeInterface(superClass.getInterfaces()[i], classes);				
82  				}
83  			}
84  		}
85  		classes.remove(Object.class);
86  		
87  		// save the result
88  		subclassesCache.put(cls, new SoftReference(classes));
89  		
90  		return classes;
91  	}
92  	
93  	private static HashMapMap<Class, Boolean, SoftReference<List<Field>>> allFieldsCache = new HashMapMap<Class, Boolean, SoftReference<List<Field>>>(); 
94  	
95  	public static List<Field> getAllFields(Class cls, boolean includeStatic) {
96  		SoftReference<List<Field>> fieldsRef;
97  		synchronized(allFieldsCache) {
98  			fieldsRef = allFieldsCache.get(cls, includeStatic);
99  		}
100 		List<Field> fields = null;
101 		if (fieldsRef != null) {
102 			fields = fieldsRef.get();
103 			if (fields != null) return fields;
104 		}
105 		fields = new ArrayList<Field>();
106 		Class clz = cls;
107 		if (includeStatic) {
108 			while (!clz.equals(Object.class)) {
109 				MyCollections.toList(clz.getDeclaredFields(), fields);
110 				clz = clz.getSuperclass();
111 			}
112 		} else {
113 			ObjectFilter<Field> filterStatic = new ObjectFilter<Field>() {
114 				@Override
115 				public boolean accept(Field object) {
116 					return !Modifier.isStatic(object.getModifiers());
117 				}
118 				
119 			};
120 			while (!clz.equals(Object.class)) {
121 				MyCollections.toList(clz.getDeclaredFields(), fields, filterStatic);
122 				clz = clz.getSuperclass();
123 			}
124 		}
125 		synchronized(allFieldsCache) {
126 			allFieldsCache.put(cls, includeStatic, new SoftReference<List<Field>>(fields));
127 		}
128 		return fields;
129 	}
130 	
131 	public static String getMethodSignature(Method method) {
132 		StringBuffer sb = new StringBuffer();
133 		sb.append(method.getDeclaringClass());
134 		sb.append("#");
135 		sb.append(method.getReturnType().getSimpleName());
136 		sb.append(" ");
137 		sb.append(method.getName());
138 		sb.append("(");
139 		int arg = 0;
140 		for (Class type : method.getParameterTypes()) {
141 			if (arg > 0) sb.append(", ");
142 			sb.append(type.toString());
143 			sb.append(" ");
144 			sb.append("arg");
145 			sb.append(arg++);
146 		}
147 		sb.append(")");
148 		return sb.toString();
149 	}
150 	
151 }