Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
ParamReader |
|
| 0.0;0 | ||||
ParamReader$MethodInfo |
|
| 0.0;0 |
1 | /** | |
2 | * Licensed to the Apache Software Foundation (ASF) under one | |
3 | * or more contributor license agreements. See the NOTICE file | |
4 | * distributed with this work for additional information | |
5 | * regarding copyright ownership. The ASF licenses this file | |
6 | * to you under the Apache License, Version 2.0 (the | |
7 | * "License"); you may not use this file except in compliance | |
8 | * with the License. You may obtain a copy of the License at | |
9 | * | |
10 | * http://www.apache.org/licenses/LICENSE-2.0 | |
11 | * | |
12 | * Unless required by applicable law or agreed to in writing, | |
13 | * software distributed under the License is distributed on an | |
14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
15 | * KIND, either express or implied. See the License for the | |
16 | * specific language governing permissions and limitations | |
17 | * under the License. | |
18 | */ | |
19 | ||
20 | package org.mule.config.spring.util; | |
21 | ||
22 | // import org.apache.axis.utils.Messages; | |
23 | ||
24 | import java.io.IOException; | |
25 | import java.lang.reflect.Constructor; | |
26 | import java.lang.reflect.Member; | |
27 | import java.lang.reflect.Method; | |
28 | import java.lang.reflect.Modifier; | |
29 | import java.lang.reflect.Proxy; | |
30 | import java.util.HashMap; | |
31 | import java.util.Map; | |
32 | ||
33 | /** | |
34 | * This is the class file reader for obtaining the parameter names for declared | |
35 | * methods in a class. The class must have debugging attributes for us to obtain this | |
36 | * information. | |
37 | * <p> | |
38 | * This does not work for inherited methods. To obtain parameter names for inherited | |
39 | * methods, you must use a paramReader for the class that originally declared the | |
40 | * method. | |
41 | * <p> | |
42 | * don't get tricky, it's the bare minimum. Instances of this class are not | |
43 | * threadsafe -- don't share them. | |
44 | * <p> | |
45 | * | |
46 | * @author Edwin Smith, Macromedia | |
47 | */ | |
48 | public class ParamReader extends ClassReader | |
49 | { | |
50 | private String methodName; | |
51 | 0 | private Map<String, MethodInfo> methods = new HashMap<String, MethodInfo>(); |
52 | private Class[] paramTypes; | |
53 | ||
54 | /** | |
55 | * process a class file, given it's class. We'll use the defining classloader to | |
56 | * locate the bytecode. | |
57 | * | |
58 | * @param c | |
59 | * @throws IOException | |
60 | */ | |
61 | public ParamReader(Class c) throws IOException | |
62 | { | |
63 | 0 | this(getBytes(c)); |
64 | 0 | } |
65 | ||
66 | /** | |
67 | * process the given class bytes directly. | |
68 | * | |
69 | * @param b | |
70 | * @throws IOException | |
71 | */ | |
72 | public ParamReader(byte[] b) throws IOException | |
73 | { | |
74 | 0 | super(b, findAttributeReaders(ParamReader.class)); |
75 | ||
76 | // check the magic number | |
77 | 0 | if (readInt() != 0xCAFEBABE) |
78 | { | |
79 | // not a class file! | |
80 | 0 | throw new IOException(); |
81 | } | |
82 | ||
83 | 0 | readShort(); // minor version |
84 | 0 | readShort(); // major version |
85 | ||
86 | 0 | readCpool(); // slurp in the constant pool |
87 | ||
88 | 0 | readShort(); // access flags |
89 | 0 | readShort(); // this class name |
90 | 0 | readShort(); // super class name |
91 | ||
92 | 0 | int count = readShort(); // ifaces count |
93 | 0 | for (int i = 0; i < count; i++) |
94 | { | |
95 | 0 | readShort(); // interface index |
96 | } | |
97 | ||
98 | 0 | count = readShort(); // fields count |
99 | 0 | for (int i = 0; i < count; i++) |
100 | { | |
101 | 0 | readShort(); // access flags |
102 | 0 | readShort(); // name index |
103 | 0 | readShort(); // descriptor index |
104 | 0 | skipAttributes(); // field attributes |
105 | } | |
106 | ||
107 | 0 | count = readShort(); // methods count |
108 | 0 | for (int i = 0; i < count; i++) |
109 | { | |
110 | 0 | readShort(); // access flags |
111 | 0 | int m = readShort(); // name index |
112 | 0 | String name = resolveUtf8(m); |
113 | 0 | int d = readShort(); // descriptor index |
114 | 0 | this.methodName = name + resolveUtf8(d); |
115 | 0 | readAttributes(); // method attributes |
116 | } | |
117 | ||
118 | 0 | } |
119 | ||
120 | /** | |
121 | * Retrieve a list of function parameter names from a method Returns null if | |
122 | * unable to read parameter names (i.e. bytecode not built with debug). | |
123 | */ | |
124 | public static String[] getParameterNamesFromDebugInfo(Method method) | |
125 | { | |
126 | // Don't worry about it if there are no params. | |
127 | 0 | int numParams = method.getParameterTypes().length; |
128 | 0 | if (numParams == 0) |
129 | { | |
130 | 0 | return null; |
131 | } | |
132 | ||
133 | // get declaring class | |
134 | 0 | Class c = method.getDeclaringClass(); |
135 | ||
136 | // Don't worry about it if the class is a Java dynamic proxy | |
137 | 0 | if (Proxy.isProxyClass(c)) |
138 | { | |
139 | 0 | return null; |
140 | } | |
141 | ||
142 | try | |
143 | { | |
144 | // get a parameter reader | |
145 | 0 | ParamReader pr = new ParamReader(c); |
146 | // get the parameter names | |
147 | 0 | return pr.getParameterNames(method); |
148 | } | |
149 | 0 | catch (IOException e) |
150 | { | |
151 | // log it and leave | |
152 | // log.info(Messages.getMessage("error00") + ":" + e); | |
153 | 0 | return null; |
154 | } | |
155 | } | |
156 | ||
157 | public void readCode() throws IOException | |
158 | { | |
159 | 0 | readShort(); // max stack |
160 | 0 | int maxLocals = readShort(); // max locals |
161 | ||
162 | 0 | MethodInfo info = new MethodInfo(maxLocals); |
163 | 0 | if (methods != null && methodName != null) |
164 | { | |
165 | 0 | methods.put(methodName, info); |
166 | } | |
167 | ||
168 | 0 | skipFully(readInt()); // code |
169 | 0 | skipFully(8 * readShort()); // exception table |
170 | // read the code attributes (recursive). This is where | |
171 | // we will find the LocalVariableTable attribute. | |
172 | 0 | readAttributes(); |
173 | 0 | } |
174 | ||
175 | /** | |
176 | * return the names of the declared parameters for the given constructor. If we | |
177 | * cannot determine the names, return null. The returned array will have one name | |
178 | * per parameter. The length of the array will be the same as the length of the | |
179 | * Class[] array returned by Constructor.getParameterTypes(). | |
180 | * | |
181 | * @param ctor | |
182 | * @return String[] array of names, one per parameter, or null | |
183 | */ | |
184 | public String[] getParameterNames(Constructor ctor) | |
185 | { | |
186 | 0 | paramTypes = ctor.getParameterTypes(); |
187 | 0 | return getParameterNames(ctor, paramTypes); |
188 | } | |
189 | ||
190 | /** | |
191 | * return the names of the declared parameters for the given method. If we cannot | |
192 | * determine the names, return null. The returned array will have one name per | |
193 | * parameter. The length of the array will be the same as the length of the | |
194 | * Class[] array returned by Method.getParameterTypes(). | |
195 | * | |
196 | * @param method | |
197 | * @return String[] array of names, one per parameter, or null | |
198 | */ | |
199 | public String[] getParameterNames(Method method) | |
200 | { | |
201 | 0 | paramTypes = method.getParameterTypes(); |
202 | 0 | return getParameterNames(method, paramTypes); |
203 | } | |
204 | ||
205 | protected String[] getParameterNames(Member member, Class[] pTypes) | |
206 | { | |
207 | // look up the names for this method | |
208 | 0 | MethodInfo info = (MethodInfo) methods.get(getSignature(member, pTypes)); |
209 | ||
210 | // we know all the local variable names, but we only need to return | |
211 | // the names of the parameters. | |
212 | ||
213 | 0 | if (info != null) |
214 | { | |
215 | 0 | String[] paramNames = new String[pTypes.length]; |
216 | 0 | int j = Modifier.isStatic(member.getModifiers()) ? 0 : 1; |
217 | ||
218 | 0 | boolean found = false; // did we find any non-null names |
219 | 0 | for (int i = 0; i < paramNames.length; i++) |
220 | { | |
221 | 0 | if (info.names[j] != null) |
222 | { | |
223 | 0 | found = true; |
224 | 0 | paramNames[i] = info.names[j]; |
225 | } | |
226 | 0 | j++; |
227 | 0 | if (pTypes[i] == double.class || pTypes[i] == long.class) |
228 | { | |
229 | // skip a slot for 64bit params | |
230 | 0 | j++; |
231 | } | |
232 | } | |
233 | ||
234 | 0 | if (found) |
235 | { | |
236 | 0 | return paramNames; |
237 | } | |
238 | else | |
239 | { | |
240 | 0 | return null; |
241 | } | |
242 | } | |
243 | else | |
244 | { | |
245 | 0 | return null; |
246 | } | |
247 | } | |
248 | ||
249 | private static class MethodInfo | |
250 | { | |
251 | String[] names; | |
252 | ||
253 | public MethodInfo(int maxLocals) | |
254 | 0 | { |
255 | 0 | names = new String[maxLocals]; |
256 | 0 | } |
257 | } | |
258 | ||
259 | private MethodInfo getMethodInfo() | |
260 | { | |
261 | 0 | MethodInfo info = null; |
262 | 0 | if (methods != null && methodName != null) |
263 | { | |
264 | 0 | info = (MethodInfo) methods.get(methodName); |
265 | } | |
266 | 0 | return info; |
267 | } | |
268 | ||
269 | /** | |
270 | * this is invoked when a LocalVariableTable attribute is encountered. | |
271 | * | |
272 | * @throws IOException | |
273 | */ | |
274 | public void readLocalVariableTable() throws IOException | |
275 | { | |
276 | 0 | int len = readShort(); // table length |
277 | 0 | MethodInfo info = getMethodInfo(); |
278 | 0 | for (int j = 0; j < len; j++) |
279 | { | |
280 | 0 | readShort(); // start pc |
281 | 0 | readShort(); // length |
282 | 0 | int nameIndex = readShort(); // name_index |
283 | 0 | readShort(); // descriptor_index |
284 | 0 | int index = readShort(); // local index |
285 | 0 | if (info != null) |
286 | { | |
287 | 0 | info.names[index] = resolveUtf8(nameIndex); |
288 | } | |
289 | } | |
290 | 0 | } |
291 | } |