1 package org.kite9.framework.model;
2
3 import java.lang.reflect.Field;
4 import java.lang.reflect.Method;
5 import java.util.LinkedHashSet;
6 import java.util.Set;
7
8 import org.kite9.framework.common.Kite9ProcessingException;
9
10 /***
11 * Handle to a class member (method or field).
12 * Also contains static utility functions for converting from string name of class back into
13 * Class object, and doing the same with methods and fields.
14 *
15 * @author moffatr
16 *
17 */
18 public class MemberHandle implements Comparable<MemberHandle> {
19
20 public enum MemberType {
21 FIELD, METHOD
22 };
23
24 public MemberHandle(String className, String memberName, MemberType mt, String params) {
25 super();
26 this.className = className;
27 this.methodName = memberName;
28 this.memberType = mt;
29 this.params = params;
30 }
31
32 public MemberHandle(Method m) {
33 super();
34 this.className = convertClass(m.getDeclaringClass());
35 this.methodName = m.getName();
36 this.memberType = MemberType.METHOD;
37 this.params = Type.getMethodDescriptor(m);
38 }
39
40 public MemberHandle(Field f) {
41 super();
42 this.className = convertClass(f.getDeclaringClass());
43 this.methodName = f.getName();
44 this.memberType = MemberType.FIELD;
45 this.params = null;
46 }
47
48 public static String convertClass(Class<?> clazz) {
49 return clazz.getName().replace(".", "/");
50 }
51
52 public static String convertParams(Class<?>[] params2) {
53 StringBuffer sb = new StringBuffer(100);
54 for (int i = 0; i < params2.length; i++) {
55 sb.append(convertClass(params2[i]));
56 if (i < params2.length - 1) {
57 sb.append(";");
58 }
59 }
60
61 return sb.toString();
62 }
63
64 private String className;
65 private String methodName;
66 private MemberType memberType;
67 private String params;
68
69 public String getClassName() {
70 return className;
71 }
72
73 public String getMethodName() {
74 return methodName;
75 }
76
77 public String getParams() {
78 return params;
79 }
80
81 @Override
82 public String toString() {
83 return className + "/" + methodName;
84 }
85
86 public MemberType getMemberType() {
87 return memberType;
88 }
89
90 @Override
91 public int hashCode() {
92 final int prime = 31;
93 int result = 1;
94 result = prime * result + ((className == null) ? 0 : className.hashCode());
95 result = prime * result + ((memberType == null) ? 0 : memberType.hashCode());
96 result = prime * result + ((methodName == null) ? 0 : methodName.hashCode());
97 result = prime * result + ((params == null) ? 0 : params.hashCode());
98 return result;
99 }
100
101 @Override
102 public boolean equals(Object obj) {
103 if (this == obj)
104 return true;
105 if (obj == null)
106 return false;
107 if (getClass() != obj.getClass())
108 return false;
109 MemberHandle other = (MemberHandle) obj;
110 if (className == null) {
111 if (other.className != null)
112 return false;
113 } else if (!className.equals(other.className))
114 return false;
115 if (memberType == null) {
116 if (other.memberType != null)
117 return false;
118 } else if (!memberType.equals(other.memberType))
119 return false;
120 if (methodName == null) {
121 if (other.methodName != null)
122 return false;
123 } else if (!methodName.equals(other.methodName))
124 return false;
125 if (params == null) {
126 if (other.params != null)
127 return false;
128 } else if (!params.equals(other.params))
129 return false;
130 return true;
131 }
132
133 public static Set<Class<?>> hydrateClasses(Set<String> classNames, ClassLoader cl) {
134 Set<Class<?>> out = new LinkedHashSet<Class<?>>(classNames.size());
135 for (String n : classNames) {
136 out.add(hydrateClass(n, cl));
137 }
138
139 return out;
140 }
141
142 public static Set<Method> hydrateMethods(Set<MemberHandle> methods, ClassLoader cl) {
143 Set<Method> out = new LinkedHashSet<Method>(methods.size());
144 for (MemberHandle n : methods) {
145 out.add(hydrateMethod(n, cl));
146 }
147
148 return out;
149 }
150
151 public static Set<Field> hydrateFields(Set<MemberHandle> fields, ClassLoader cl) {
152 Set<Field> out = new LinkedHashSet<Field>(fields.size());
153 for (MemberHandle n : fields) {
154 out.add(hydrateField(n, cl));
155 }
156
157 return out;
158 }
159
160
161 public static Class<?> hydrateClass(String className, ClassLoader cl) {
162 try {
163 String name = className.replace("/", ".");
164 Class<?> c = cl.loadClass(name);
165
166 return c;
167 } catch (ClassNotFoundException e) {
168 throw new Kite9ProcessingException("Could not load class: ", e);
169 }
170 }
171
172 public static Class<?>[] hydrateParams(Type[] types, ClassLoader cl) {
173 if ((types == null) || (types.length == 0)) {
174 return new Class<?>[0];
175 }
176
177 Class<?>[] out = new Class<?>[types.length];
178 for (int i = 0; i < types.length; i++) {
179 out[i] = hydrateClass(types[i].getClassName(), cl);
180 }
181
182 return out;
183 }
184
185 public static Method hydrateMethod(MemberHandle method, ClassLoader cl) {
186 try {
187 Type[] args = Type.getArgumentTypes(method.getParams());
188 Class<?> c = hydrateClass(method.getClassName(), cl);
189 Class<?>[] params = hydrateParams(args, cl);
190 Method m = c.getDeclaredMethod(method.getMethodName(), params);
191 return m;
192 } catch (NoSuchMethodException e) {
193 throw new Kite9ProcessingException("Could not find method: ", e);
194 }
195 }
196
197 public static Field hydrateField(MemberHandle field, ClassLoader cl) {
198 try {
199 Class<?> c = hydrateClass(field.getClassName(), cl);
200 Field f = c.getDeclaredField(field.getMethodName());
201 return f;
202 } catch (NoSuchFieldException e) {
203 throw new Kite9ProcessingException("Could not find field: ", e);
204 }
205 }
206
207 public static String convertClassName(Class<?> c) {
208 return c.getName().replace(".", "/");
209 }
210
211 public static String convertPackageName(Package p) {
212 return p.getName().replace(".", "/");
213 }
214
215 public int compareTo(MemberHandle o) {
216 int res = this.getMethodName().compareTo(o.getMethodName());
217 if (res==0) {
218 if (this.getParams()!=null) {
219 return (this.getParams().compareTo(o.getParams()));
220 } else if (o.getParams()==null) {
221 return 0;
222 } else {
223 return 1;
224 }
225
226 }
227
228 return res;
229 }
230 }