1 package attrib4j.bcel;
2
3 import java.io.DataOutputStream;
4 import java.io.File;
5 import java.io.FileOutputStream;
6 import java.io.IOException;
7 import java.net.URLClassLoader;
8 import java.util.Arrays;
9 import java.util.StringTokenizer;
10
11
12 import org.apache.bcel.classfile.Attribute;
13 import org.apache.bcel.classfile.ConstantPool;
14 import org.apache.bcel.classfile.Field;
15 import org.apache.bcel.classfile.JavaClass;
16 import org.apache.bcel.classfile.Method;
17 import org.apache.bcel.classfile.Unknown;
18 import org.apache.bcel.generic.ClassGen;
19 import org.apache.bcel.generic.ConstantPoolGen;
20 import org.apache.bcel.generic.FieldGen;
21 import org.apache.bcel.generic.MethodGen;
22
23
24 import attrib4j.AttributeException;
25 import attrib4j.ClassAnnotator;
26 import attrib4j.Log;
27
28
29 import com.sun.javadoc.MethodDoc;
30
31 /***
32 * @author Mark.Pollack
33 */
34 public abstract class AbstractBCELClassAnnotator implements ClassAnnotator {
35
36 protected static Class createFromPackageSearch(
37 String baseClassname,
38 URLClassLoader classloader,
39 String[] attributePackages)
40 throws AttributeException {
41
42 boolean foundClass = false;
43 Class returnClass = null;
44 Exception returnException = null;
45 //TODO Use Set instead?
46 Log.debug("AbstractBCELClassAnnotator", "Creating from package search");
47 for (int i = 0; i < attributePackages.length; i++) {
48 try {
49 Log.debug(
50 "AbstractBCELClassAnnotator",
51 "Trying with package name = " + attributePackages[i]);
52 returnClass =
53 Class.forName(
54 attributePackages[i] + "." + baseClassname,
55 true,
56 classloader);
57 foundClass = true;
58 break;
59 } catch (ClassNotFoundException e) {
60 try {
61 returnClass =
62 Class.forName(
63 attributePackages[i]
64 + "."
65 + baseClassname
66 + "Attribute",
67 true,
68 classloader);
69 foundClass = true;
70 } catch (ClassNotFoundException e2) {
71 returnException = e2;
72 }
73 }
74 }
75 if (!foundClass) {
76 if (returnException != null) {
77 throw new AttributeException(returnException);
78 } else {
79 throw new AttributeException(
80 "Could not create Attribute class " + baseClassname);
81 }
82 } else {
83 return returnClass;
84 }
85 }
86
87 /***
88 * Internal routine to guess (and create) the parameter instance from
89 * the text passed in and the type it's supposed to be (from the
90 * constructor). This method handles String, Boolean, Byte, Short,
91 * Integer, Long, Float, and Double parameter types.
92 *
93 * @param ctorParamType The class of the positional parameter in the
94 * attribute constructor.
95 * @param paramText The string value of this paramemter as given in
96 * in the Javadoc tag.
97 * @return An instance of the correct parameter class initialized to
98 * the value specified by the parameter text.
99 */
100 protected static Object guessParam(Class ctorParamType, String paramText) {
101 if (ctorParamType.equals(String.class)) {
102 if (paramText.startsWith("\"") && paramText.endsWith("\"")) {
103 return paramText.substring(1, paramText.length() - 1);
104 }
105 return null;
106 }
107 if (ctorParamType.equals(Boolean.class)
108 || ctorParamType.equals(boolean.class)) {
109 if (paramText.equals("true")) {
110 return new Boolean(true);
111 }
112 if (paramText.equals("false")) {
113 return new Boolean(false);
114 }
115 return null;
116 }
117 if (ctorParamType.equals(Byte.class)
118 || ctorParamType.equals(byte.class)) {
119 try {
120 return new Byte(paramText);
121 } catch (NumberFormatException pe) {
122 return null;
123 }
124 }
125 if (ctorParamType.equals(Short.class)
126 || ctorParamType.equals(short.class)) {
127 try {
128 return new Short(paramText);
129 } catch (NumberFormatException pe) {
130 return null;
131 }
132 }
133 if (ctorParamType.equals(Integer.class)
134 || ctorParamType.equals(int.class)) {
135 try {
136 return new Integer(paramText);
137 } catch (NumberFormatException pe) {
138 return null;
139 }
140 }
141 if (ctorParamType.equals(Long.class)
142 || ctorParamType.equals(long.class)) {
143 try {
144 return new Long(paramText);
145 } catch (NumberFormatException pe) {
146 return null;
147 }
148 }
149 if (ctorParamType.equals(Float.class)
150 || ctorParamType.equals(float.class)) {
151 try {
152 return new Float(paramText);
153 } catch (NumberFormatException pe) {
154 return null;
155 }
156 }
157 if (ctorParamType.equals(Double.class)
158 || ctorParamType.equals(double.class)) {
159 try {
160 return new Double(paramText);
161 } catch (NumberFormatException pe) {
162 return null;
163 }
164 }
165
166 return null;
167 }
168
169 /***
170 * Internal routine to pick out a classname from text looking something
171 * like:
172 * "@attribute attrib4j.examples.attributes.DebugAttribute(true, 12)"
173 *
174 * @param fullAttributeText The text of the attribute javadoc tag.
175 * @return The classname to be created as parsed from the javadoc tag.
176 */
177 protected static String parseAttributeClassName(String fullAttributeText) {
178 String cn;
179 if (fullAttributeText.indexOf("(") > -1) {
180 cn =
181 fullAttributeText
182 .substring(0, fullAttributeText.indexOf("("))
183 .trim();
184 } else {
185 cn = fullAttributeText;
186 }
187 return cn;
188 }
189
190 /***
191 * Internal routine to pick out parameters from text looking something like
192 * "@attribute com.javageeks.attributes.DebugAttribute(true, 12)"
193 *
194 * @param fullAttributeText The text of the attribute javadoc tag.
195 * @return An array of positional parameters that will be used for
196 * for the constructor of the attribute.
197 */
198 protected static String[] parseAttributeParams(String fullAttributeText) {
199
200 String[] p = new String[0];
201 int paramsStart = fullAttributeText.indexOf("(");
202 //fixed small bug, was looking for the first index of the closing paren..
203 int paramsEnd = fullAttributeText.lastIndexOf(")");
204
205 if (paramsStart == -1
206 || // No ()'s at all
207 (paramsStart == (paramsEnd + 1))) {
208 // ()'s right next to each other
209 return p;
210 } else {
211 String paramText =
212 fullAttributeText.substring(paramsStart + 1, paramsEnd);
213 StringTokenizer st = new StringTokenizer(paramText, ",");
214 p = new String[st.countTokens()];
215 int count = 0;
216 while (st.hasMoreTokens()) {
217 p[count++] = st.nextToken().trim();
218 }
219 return p;
220 }
221 }
222
223 protected ClassGen _classGen;
224
225 protected ConstantPool _constantPool;
226
227 protected ConstantPoolGen _constantPoolGen;
228
229 protected JavaClass _javaClass;
230
231 /* (non-Javadoc)
232 * @see attrib4j.ClassAnnotator#createAttributeInstance(java.lang.String, java.net.URLClassLoader, java.lang.String[])
233 */
234 public abstract Object createAttributeInstance(
235 String text,
236 URLClassLoader classLoader,
237 String[] attributePackages);
238
239
240 public abstract byte[] createBytesFromAttribute(Object attribute);
241
242 /***
243 * {@inheritDoc}
244 * @see attrib4j.ClassAnnotator#insertClassAttribute(java.lang.Object)
245 */
246 public void insertClassAttribute(Object attribute) {
247 byte[] serializedAttribute = createBytesFromAttribute(attribute);
248
249 int nameIndex = _constantPoolGen.addUtf8("Custom");
250
251 Attribute attr =
252 new Unknown(
253 nameIndex,
254 serializedAttribute.length,
255 serializedAttribute,
256 _constantPoolGen.getConstantPool());
257
258 _classGen.addAttribute(attr);
259
260 }
261
262
263 /***
264 * {@inheritDoc}
265 * @see attrib4j.ClassAnnotator#insertFieldAttribute(java.lang.String, java.lang.Object)
266 */
267 public void insertFieldAttribute(String field, Object attribute) {
268 byte[] serializedAttribute = createBytesFromAttribute(attribute);
269 //get list of fields inthe class from bcel.
270 Field[] classfileField = _classGen.getFields();
271
272 for (int i = 0; i < classfileField.length; i++) {
273 if (classfileField[i].getName().equals(field)) {
274 Log.debug(
275 "BCELClassAnnotator",
276 "Inserting attribute for fieldname = " + field);
277 FieldGen fieldGen =
278 new FieldGen(classfileField[i], _constantPoolGen);
279 int nameIndex = _constantPoolGen.addUtf8("Custom");
280 Attribute attr =
281 new Unknown(
282 nameIndex,
283 serializedAttribute.length,
284 serializedAttribute,
285 _constantPoolGen.getConstantPool());
286 fieldGen.addAttribute(attr);
287 Field newField = fieldGen.getField();
288 _classGen.replaceField(classfileField[i], newField);
289 }
290 }
291
292 }
293
294
295 /***
296 * {@inheritDoc}
297 * @see attrib4j.ClassAnnotator#insertMethodAttribute(com.sun.javadoc.MethodDoc, java.lang.Object)
298 */
299 public void insertMethodAttribute(MethodDoc methodDoc, Object attribute) {
300 byte[] serializedAttribute = createBytesFromAttribute(attribute);
301 Log.debug("BCELClassAnnotator", "-------------");
302
303 String[] methodParamTypes = new String[methodDoc.parameters().length];
304 for (int i = 0; i < methodParamTypes.length; i++) {
305 methodParamTypes[i] = methodDoc.parameters()[i].typeName();
306 }
307
308 //get list of methods in the class from bcel
309 Method[] classfileMethod = _classGen.getMethods();
310 for (int i = 0; i < classfileMethod.length; i++) {
311 //Log.log("classfileMethod = " + classfileMethod[i].getName());
312 //match classname
313 if (classfileMethod[i].getName().equals(methodDoc.name())) {
314 if (Arrays
315 .equals(
316 methodParamTypes,
317 DescriptorUtil.convertToJavaFormat(
318 classfileMethod[i].getSignature()))) {
319 Log.debug(
320 "BCELClassAnnotator",
321 "matched methodname = " + methodDoc.name());
322 Log.debug(
323 "BCELClassAnnotator",
324 "BCEL classfileMethod sig = "
325 + classfileMethod[i].getSignature());
326 Log.debug(
327 "BCELClassAnnotator",
328 "javadocMethod sig = "
329 + methodDoc.signature()
330 + " return type = "
331 + methodDoc.returnType().qualifiedTypeName());
332 MethodGen methodGen =
333 new MethodGen(
334 classfileMethod[i],
335 _javaClass.getClassName(),
336 _constantPoolGen);
337
338 int nameIndex = _constantPoolGen.addUtf8("Custom");
339 Attribute attr =
340 new Unknown(
341 nameIndex,
342 serializedAttribute.length,
343 serializedAttribute,
344 _constantPoolGen.getConstantPool());
345 methodGen.addAttribute(attr);
346 Method newMethod = methodGen.getMethod();
347 _classGen.replaceMethod(classfileMethod[i], newMethod);
348 }
349 }
350 }
351 Log.debug("BCELClassAnnotator", "-------------");
352 }
353
354
355 public void write(String destDir) {
356
357 try {
358 _classGen.setConstantPool(_constantPoolGen);
359 //_classGen.setConstantPool(new ConstantPoolGen(_constantPool));
360 JavaClass newJavaClass = _classGen.getJavaClass();
361
362 String path =
363 destDir
364 + "/"
365 + newJavaClass.getClassName().replace('.', '/')
366 + ".class";
367 File f = new File(path);
368 File parentFile = f.getParentFile();
369
370 boolean exists = parentFile.exists();
371 if (!exists) {
372 //Directory does not exist
373 //create all directories in the path
374 boolean success = parentFile.mkdirs();
375 if (!success) {
376 //TODO: Introduce exception handling into interface?
377 //throw new AttributeException("Could not create directory " + parentFile.toString());
378 Log.log(
379 "Could not create directory to write new .class file. "
380 + parentFile.toString(),
381 Log.CRITICAL,
382 this);
383 }
384 }
385
386 FileOutputStream fout = new FileOutputStream(path);
387 DataOutputStream out = new DataOutputStream(fout);
388 newJavaClass.dump(out);
389 fout.close();
390 } catch (IOException ioEx) {
391 ioEx.printStackTrace();
392 }
393
394 }
395
396
397
398
399 }
This page was automatically generated by Maven