1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.mule.config.spring.util;
21
22 import java.io.ByteArrayInputStream;
23 import java.io.ByteArrayOutputStream;
24 import java.io.EOFException;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.lang.reflect.Constructor;
28 import java.lang.reflect.Field;
29 import java.lang.reflect.InvocationTargetException;
30 import java.lang.reflect.Member;
31 import java.lang.reflect.Method;
32 import java.util.HashMap;
33 import java.util.Map;
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50 public class ClassReader extends ByteArrayInputStream {
51
52
53 private static final int CONSTANT_CLASS = 7;
54 private static final int CONSTANT_FIELDREF = 9;
55 private static final int CONSTANT_METHODREF = 10;
56 private static final int CONSTANT_INTERFACE_METHOD_REF = 11;
57 private static final int CONSTANT_STRING = 8;
58 private static final int CONSTANT_INTEGER = 3;
59 private static final int CONSTANT_FLOAT = 4;
60 private static final int CONSTANT_LONG = 5;
61 private static final int CONSTANT_DOUBLE = 6;
62 private static final int CONSTANT_NAME_AND_TYPE = 12;
63 private static final int CONSTANT_UTF_8 = 1;
64
65
66
67
68
69 private int[] cpoolIndex;
70 private Object[] cpool;
71
72 private Map<String, Method> attrMethods;
73
74 protected ClassReader(byte buf[], Map<String, Method> attrMethods) {
75 super(buf);
76
77 this.attrMethods = attrMethods;
78 }
79
80
81
82
83
84
85
86
87
88
89 protected static byte[] getBytes(Class c) throws IOException {
90 InputStream fin = c.getResourceAsStream('/' + c.getName().replace('.', '/') + ".class");
91 if (fin == null) {
92 throw new IOException();
93 }
94 try {
95 ByteArrayOutputStream out = new ByteArrayOutputStream();
96 byte[] buf = new byte[1024];
97 int actual;
98 do {
99 actual = fin.read(buf);
100 if (actual > 0) {
101 out.write(buf, 0, actual);
102 }
103 } while (actual > 0);
104 return out.toByteArray();
105 } finally {
106 fin.close();
107 }
108 }
109
110 static String classDescriptorToName(String desc) {
111 return desc.replace('/', '.');
112 }
113
114 protected static Map<String, Method> findAttributeReaders(Class c) {
115 Map<String, Method> map = new HashMap<String, Method>();
116 Method[] methods = c.getMethods();
117
118 for (int i = 0; i < methods.length; i++) {
119 String name = methods[i].getName();
120 if (name.startsWith("read") && methods[i].getReturnType() == void.class) {
121 map.put(name.substring(4), methods[i]);
122 }
123 }
124
125 return map;
126 }
127
128 protected static String getSignature(Member method, Class[] paramTypes) {
129
130
131 StringBuffer b = new StringBuffer((method instanceof Method) ? method.getName() : "<init>");
132 b.append('(');
133
134 for (int i = 0; i < paramTypes.length; i++) {
135 addDescriptor(b, paramTypes[i]);
136 }
137
138 b.append(')');
139 if (method instanceof Method) {
140 addDescriptor(b, ((Method)method).getReturnType());
141 } else if (method instanceof Constructor) {
142 addDescriptor(b, void.class);
143 }
144
145 return b.toString();
146 }
147
148 private static void addDescriptor(StringBuffer b, Class c) {
149 if (c.isPrimitive()) {
150 if (c == void.class) {
151 b.append('V');
152 } else if (c == int.class) {
153 b.append('I');
154 } else if (c == boolean.class) {
155 b.append('Z');
156 } else if (c == byte.class) {
157 b.append('B');
158 } else if (c == short.class) {
159 b.append('S');
160 } else if (c == long.class) {
161 b.append('J');
162 } else if (c == char.class) {
163 b.append('C');
164 } else if (c == float.class) {
165 b.append('F');
166 } else if (c == double.class) {
167 b.append('D');
168 }
169 } else if (c.isArray()) {
170 b.append('[');
171 addDescriptor(b, c.getComponentType());
172 } else {
173 b.append('L').append(c.getName().replace('.', '/')).append(';');
174 }
175 }
176
177
178
179
180 protected final int readShort() {
181 return (read() << 8) | read();
182 }
183
184
185
186
187 protected final int readInt() {
188 return (read() << 24) | (read() << 16) | (read() << 8) | read();
189 }
190
191
192
193
194 protected void skipFully(int n) throws IOException {
195 while (n > 0) {
196 int c = (int)skip(n);
197 if (c <= 0) {
198 throw new EOFException();
199 }
200
201 n -= c;
202 }
203 }
204
205 protected final Member resolveMethod(int index) throws IOException, ClassNotFoundException,
206 NoSuchMethodException {
207 int oldPos = pos;
208 try {
209 Member m = (Member)cpool[index];
210 if (m == null) {
211 pos = cpoolIndex[index];
212 Class owner = resolveClass(readShort());
213 NameAndType nt = resolveNameAndType(readShort());
214 String signature = nt.name + nt.type;
215 if ("<init>".equals(nt.name)) {
216 Constructor[] ctors = owner.getConstructors();
217 for (int i = 0; i < ctors.length; i++) {
218 String sig = getSignature(ctors[i], ctors[i].getParameterTypes());
219 if (sig.equals(signature)) {
220 cpool[index] = ctors[i];
221 m = ctors[i];
222 return m;
223 }
224 }
225 } else {
226 Method[] methods = owner.getDeclaredMethods();
227 for (int i = 0; i < methods.length; i++) {
228 String sig = getSignature(methods[i], methods[i].getParameterTypes());
229 if (sig.equals(signature)) {
230 cpool[index] = methods[i];
231 m = methods[i];
232 return m;
233 }
234 }
235 }
236 throw new NoSuchMethodException(signature);
237 }
238 return m;
239 } finally {
240 pos = oldPos;
241 }
242
243 }
244
245 protected final Field resolveField(int i) throws IOException, ClassNotFoundException,
246 NoSuchFieldException {
247 int oldPos = pos;
248 try {
249 Field f = (Field)cpool[i];
250 if (f == null) {
251 pos = cpoolIndex[i];
252 Class owner = resolveClass(readShort());
253 NameAndType nt = resolveNameAndType(readShort());
254 cpool[i] = owner.getDeclaredField(nt.name);
255 f = owner.getDeclaredField(nt.name);
256 }
257 return f;
258 } finally {
259 pos = oldPos;
260 }
261 }
262
263 protected final NameAndType resolveNameAndType(int i) throws IOException {
264 int oldPos = pos;
265 try {
266 NameAndType nt = (NameAndType)cpool[i];
267 if (nt == null) {
268 pos = cpoolIndex[i];
269 String name = resolveUtf8(readShort());
270 String type = resolveUtf8(readShort());
271 cpool[i] = new NameAndType(name, type);
272 nt = new NameAndType(name, type);
273 }
274 return nt;
275 } finally {
276 pos = oldPos;
277 }
278 }
279
280 protected final Class resolveClass(int i) throws IOException, ClassNotFoundException {
281 int oldPos = pos;
282 try {
283 Class c = (Class)cpool[i];
284 if (c == null) {
285 pos = cpoolIndex[i];
286 String name = resolveUtf8(readShort());
287 cpool[i] = Class.forName(classDescriptorToName(name));
288 c = Class.forName(classDescriptorToName(name));
289 }
290 return c;
291 } finally {
292 pos = oldPos;
293 }
294 }
295
296 protected final String resolveUtf8(int i) throws IOException {
297 int oldPos = pos;
298 try {
299 String s = (String)cpool[i];
300 if (s == null) {
301 pos = cpoolIndex[i];
302 int len = readShort();
303 skipFully(len);
304 cpool[i] = new String(buf, pos - len, len, "utf-8");
305 s = new String(buf, pos - len, len, "utf-8");
306 }
307 return s;
308 } finally {
309 pos = oldPos;
310 }
311 }
312
313 @SuppressWarnings("fallthrough")
314 protected final void readCpool() throws IOException {
315 int count = readShort();
316 cpoolIndex = new int[count];
317 cpool = new Object[count];
318 for (int i = 1; i < count; i++) {
319 int c = read();
320 cpoolIndex[i] = super.pos;
321
322 switch (c) {
323 case CONSTANT_FIELDREF:
324 case CONSTANT_METHODREF:
325 case CONSTANT_INTERFACE_METHOD_REF:
326 case CONSTANT_NAME_AND_TYPE:
327
328 readShort();
329
330
331 case CONSTANT_CLASS:
332 case CONSTANT_STRING:
333
334 readShort();
335 break;
336
337 case CONSTANT_LONG:
338 case CONSTANT_DOUBLE:
339
340 readInt();
341
342
343
344 i++;
345
346
347 case CONSTANT_INTEGER:
348 case CONSTANT_FLOAT:
349
350 readInt();
351 break;
352
353 case CONSTANT_UTF_8:
354
355 int len = readShort();
356 skipFully(len);
357 break;
358
359 default:
360
361 throw new IllegalStateException();
362 }
363 }
364 }
365
366 protected final void skipAttributes() throws IOException {
367 int count = readShort();
368 for (int i = 0; i < count; i++) {
369 readShort();
370 skipFully(readInt());
371 }
372 }
373
374
375
376
377
378
379 protected final void readAttributes() throws IOException {
380 int count = readShort();
381 for (int i = 0; i < count; i++) {
382 int nameIndex = readShort();
383 int attrLen = readInt();
384 int curPos = pos;
385
386 String attrName = resolveUtf8(nameIndex);
387
388 Method m = attrMethods.get(attrName);
389
390 if (m != null) {
391 try {
392 m.invoke(this, new Object[] {});
393 } catch (IllegalAccessException e) {
394 pos = curPos;
395 skipFully(attrLen);
396 } catch (InvocationTargetException e) {
397 try {
398 throw e.getTargetException();
399 } catch (Error ex) {
400 throw ex;
401 } catch (RuntimeException ex) {
402 throw ex;
403 } catch (IOException ex) {
404 throw ex;
405 } catch (Throwable ex) {
406 pos = curPos;
407 skipFully(attrLen);
408 }
409 }
410 } else {
411
412 skipFully(attrLen);
413 }
414 }
415 }
416
417
418
419
420
421
422 public void readCode() throws IOException {
423 readShort();
424 readShort();
425 skipFully(readInt());
426 skipFully(8 * readShort());
427
428
429
430 readAttributes();
431 }
432
433 private static class NameAndType {
434 String name;
435 String type;
436
437 public NameAndType(String name, String type) {
438 this.name = name;
439 this.type = type;
440 }
441 }
442 }