KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > asm > util > ASMifierClassVisitor


1 /***
2  * ASM: a very small and fast Java bytecode manipulation framework
3  * Copyright (c) 2000-2005 INRIA, France Telecom
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  * 3. Neither the name of the copyright holders nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
28  * THE POSSIBILITY OF SUCH DAMAGE.
29  */

30 package com.tc.asm.util;
31
32 import java.io.FileInputStream JavaDoc;
33 import java.io.PrintWriter JavaDoc;
34
35 import com.tc.asm.AnnotationVisitor;
36 import com.tc.asm.ClassReader;
37 import com.tc.asm.ClassVisitor;
38 import com.tc.asm.FieldVisitor;
39 import com.tc.asm.MethodVisitor;
40 import com.tc.asm.Opcodes;
41 import com.tc.asm.Type;
42
43 /**
44  * A {@link ClassVisitor} that prints the ASM code that generates the classes it
45  * visits. This class visitor can be used to quickly write ASM code to generate
46  * some given bytecode: <ul> <li>write the Java source code equivalent to the
47  * bytecode you want to generate;</li> <li>compile it with <tt>javac</tt>;</li>
48  * <li>make a {@link ASMifierClassVisitor} visit this compiled class (see the
49  * {@link #main main} method);</li> <li>edit the generated source code, if
50  * necessary.</li> </ul> The source code printed when visiting the
51  * <tt>Hello</tt> class is the following: <p> <blockquote>
52  *
53  * <pre>
54  * import org.objectweb.asm.*;
55  *
56  * public class HelloDump implements Opcodes {
57  *
58  * public static byte[] dump() throws Exception {
59  *
60  * ClassWriter cw = new ClassWriter(false);
61  * FieldVisitor fv;
62  * MethodVisitor mv;
63  * AnnotationVisitor av0;
64  *
65  * cw.visit(49,
66  * ACC_PUBLIC + ACC_SUPER,
67  * &quot;Hello&quot;,
68  * null,
69  * &quot;java/lang/Object&quot;,
70  * null);
71  *
72  * cw.visitSource(&quot;Hello.java&quot;, null);
73  *
74  * {
75  * mv = cw.visitMethod(ACC_PUBLIC, &quot;&lt;init&gt;&quot;, &quot;()V&quot;, null, null);
76  * mv.visitVarInsn(ALOAD, 0);
77  * mv.visitMethodInsn(INVOKESPECIAL,
78  * &quot;java/lang/Object&quot;,
79  * &quot;&lt;init&gt;&quot;,
80  * &quot;()V&quot;);
81  * mv.visitInsn(RETURN);
82  * mv.visitMaxs(1, 1);
83  * mv.visitEnd();
84  * }
85  * {
86  * mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC,
87  * &quot;main&quot;,
88  * &quot;([Ljava/lang/String;)V&quot;,
89  * null,
90  * null);
91  * mv.visitFieldInsn(GETSTATIC,
92  * &quot;java/lang/System&quot;,
93  * &quot;out&quot;,
94  * &quot;Ljava/io/PrintStream;&quot;);
95  * mv.visitLdcInsn(&quot;hello&quot;);
96  * mv.visitMethodInsn(INVOKEVIRTUAL,
97  * &quot;java/io/PrintStream&quot;,
98  * &quot;println&quot;,
99  * &quot;(Ljava/lang/String;)V&quot;);
100  * mv.visitInsn(RETURN);
101  * mv.visitMaxs(2, 1);
102  * mv.visitEnd();
103  * }
104  * cw.visitEnd();
105  *
106  * return cw.toByteArray();
107  * }
108  * }
109  *
110  * </pre>
111  *
112  * </blockquote> where <tt>Hello</tt> is defined by: <p> <blockquote>
113  *
114  * <pre>
115  * public class Hello {
116  *
117  * public static void main(String[] args) {
118  * System.out.println(&quot;hello&quot;);
119  * }
120  * }
121  * </pre>
122  *
123  * </blockquote>
124  *
125  * @author Eric Bruneton
126  * @author Eugene Kuleshov
127  */

128 public class ASMifierClassVisitor extends ASMifierAbstractVisitor implements
129         ClassVisitor
130 {
131
132     /**
133      * Pseudo access flag used to distinguish class access flags.
134      */

135     private final static int ACCESS_CLASS = 262144;
136
137     /**
138      * Pseudo access flag used to distinguish field access flags.
139      */

140     private final static int ACCESS_FIELD = 524288;
141
142     /**
143      * Pseudo access flag used to distinguish inner class flags.
144      */

145     private static final int ACCESS_INNER = 1048576;
146
147     /**
148      * The print writer to be used to print the class.
149      */

150     protected final PrintWriter JavaDoc pw;
151
152     /**
153      * Prints the ASM source code to generate the given class to the standard
154      * output. <p> Usage: ASMifierClassVisitor [-debug] &lt;fully qualified
155      * class name or class file name&gt;
156      *
157      * @param args the command line arguments.
158      *
159      * @throws Exception if the class cannot be found, or if an IO exception
160      * occurs.
161      */

162     public static void main(final String JavaDoc[] args) throws Exception JavaDoc {
163         int i = 0;
164         boolean skipDebug = true;
165
166         boolean ok = true;
167         if (args.length < 1 || args.length > 2) {
168             ok = false;
169         }
170         if (ok && args[0].equals("-debug")) {
171             i = 1;
172             skipDebug = false;
173             if (args.length != 2) {
174                 ok = false;
175             }
176         }
177         if (!ok) {
178             System.err.println("Prints the ASM code to generate the given class.");
179             System.err.println("Usage: ASMifierClassVisitor [-debug] "
180                     + "<fully qualified class name or class file name>");
181             return;
182         }
183         ClassReader cr;
184         if (args[i].endsWith(".class") || args[i].indexOf('\\') > -1
185                 || args[i].indexOf('/') > -1) {
186             cr = new ClassReader(new FileInputStream JavaDoc(args[i]));
187         } else {
188             cr = new ClassReader(args[i]);
189         }
190         cr.accept(new ASMifierClassVisitor(new PrintWriter JavaDoc(System.out)),
191                 getDefaultAttributes(),
192                 skipDebug);
193     }
194
195     /**
196      * Constructs a new {@link ASMifierClassVisitor} object.
197      *
198      * @param pw the print writer to be used to print the class.
199      */

200     public ASMifierClassVisitor(final PrintWriter JavaDoc pw) {
201         super("cw");
202         this.pw = pw;
203     }
204
205     // ------------------------------------------------------------------------
206
// Implementation of the ClassVisitor interface
207
// ------------------------------------------------------------------------
208

209     public void visit(
210         final int version,
211         final int access,
212         final String JavaDoc name,
213         final String JavaDoc signature,
214         final String JavaDoc superName,
215         final String JavaDoc[] interfaces)
216     {
217         String JavaDoc simpleName;
218         int n = name.lastIndexOf('/');
219         if (n != -1) {
220             text.add("package asm." + name.substring(0, n).replace('/', '.')
221                     + ";\n");
222             simpleName = name.substring(n + 1);
223         } else {
224             simpleName = name;
225         }
226         text.add("import java.util.*;\n");
227         text.add("import org.objectweb.asm.*;\n");
228         text.add("import org.objectweb.asm.attrs.*;\n");
229         text.add("public class " + simpleName + "Dump implements Opcodes {\n\n");
230         text.add("public static byte[] dump () throws Exception {\n\n");
231         text.add("ClassWriter cw = new ClassWriter(false);\n");
232         text.add("FieldVisitor fv;\n");
233         text.add("MethodVisitor mv;\n");
234         text.add("AnnotationVisitor av0;\n\n");
235
236         buf.setLength(0);
237         buf.append("cw.visit(");
238         switch (version) {
239             case Opcodes.V1_1:
240                 buf.append("V1_1");
241                 break;
242             case Opcodes.V1_2:
243                 buf.append("V1_2");
244                 break;
245             case Opcodes.V1_3:
246                 buf.append("V1_3");
247                 break;
248             case Opcodes.V1_4:
249                 buf.append("V1_4");
250                 break;
251             case Opcodes.V1_5:
252                 buf.append("V1_5");
253                 break;
254             case Opcodes.V1_6:
255                 buf.append("V1_6");
256                 break;
257             default:
258                 buf.append(version);
259                 break;
260         }
261         buf.append(", ");
262         appendAccess(access | ACCESS_CLASS);
263         buf.append(", ");
264         appendConstant(name);
265         buf.append(", ");
266         appendConstant(signature);
267         buf.append(", ");
268         appendConstant(superName);
269         buf.append(", ");
270         if (interfaces != null && interfaces.length > 0) {
271             buf.append("new String[] {");
272             for (int i = 0; i < interfaces.length; ++i) {
273                 buf.append(i == 0 ? " " : ", ");
274                 appendConstant(interfaces[i]);
275             }
276             buf.append(" }");
277         } else {
278             buf.append("null");
279         }
280         buf.append(");\n\n");
281         text.add(buf.toString());
282     }
283
284     public void visitSource(final String JavaDoc file, final String JavaDoc debug) {
285         buf.setLength(0);
286         buf.append("cw.visitSource(");
287         appendConstant(file);
288         buf.append(", ");
289         appendConstant(debug);
290         buf.append(");\n\n");
291         text.add(buf.toString());
292     }
293
294     public void visitOuterClass(
295         final String JavaDoc owner,
296         final String JavaDoc name,
297         final String JavaDoc desc)
298     {
299         buf.setLength(0);
300         buf.append("cw.visitOuterClass(");
301         appendConstant(owner);
302         buf.append(", ");
303         appendConstant(name);
304         buf.append(", ");
305         appendConstant(desc);
306         buf.append(");\n\n");
307         text.add(buf.toString());
308     }
309
310     public void visitInnerClass(
311         final String JavaDoc name,
312         final String JavaDoc outerName,
313         final String JavaDoc innerName,
314         final int access)
315     {
316         buf.setLength(0);
317         buf.append("cw.visitInnerClass(");
318         appendConstant(name);
319         buf.append(", ");
320         appendConstant(outerName);
321         buf.append(", ");
322         appendConstant(innerName);
323         buf.append(", ");
324         appendAccess(access | ACCESS_INNER);
325         buf.append(");\n\n");
326         text.add(buf.toString());
327     }
328
329     public FieldVisitor visitField(
330         final int access,
331         final String JavaDoc name,
332         final String JavaDoc desc,
333         final String JavaDoc signature,
334         final Object JavaDoc value)
335     {
336         buf.setLength(0);
337         buf.append("{\n");
338         buf.append("fv = cw.visitField(");
339         appendAccess(access | ACCESS_FIELD);
340         buf.append(", ");
341         appendConstant(name);
342         buf.append(", ");
343         appendConstant(desc);
344         buf.append(", ");
345         appendConstant(signature);
346         buf.append(", ");
347         appendConstant(value);
348         buf.append(");\n");
349         text.add(buf.toString());
350         ASMifierFieldVisitor aav = new ASMifierFieldVisitor();
351         text.add(aav.getText());
352         text.add("}\n");
353         return aav;
354     }
355
356     public MethodVisitor visitMethod(
357         final int access,
358         final String JavaDoc name,
359         final String JavaDoc desc,
360         final String JavaDoc signature,
361         final String JavaDoc[] exceptions)
362     {
363         buf.setLength(0);
364         buf.append("{\n");
365         buf.append("mv = cw.visitMethod(");
366         appendAccess(access);
367         buf.append(", ");
368         appendConstant(name);
369         buf.append(", ");
370         appendConstant(desc);
371         buf.append(", ");
372         appendConstant(signature);
373         buf.append(", ");
374         if (exceptions != null && exceptions.length > 0) {
375             buf.append("new String[] {");
376             for (int i = 0; i < exceptions.length; ++i) {
377                 buf.append(i == 0 ? " " : ", ");
378                 appendConstant(exceptions[i]);
379             }
380             buf.append(" }");
381         } else {
382             buf.append("null");
383         }
384         buf.append(");\n");
385         text.add(buf.toString());
386         ASMifierMethodVisitor acv = new ASMifierMethodVisitor();
387         text.add(acv.getText());
388         text.add("}\n");
389         return acv;
390     }
391
392     public AnnotationVisitor visitAnnotation(
393         final String JavaDoc desc,
394         final boolean visible)
395     {
396         buf.setLength(0);
397         buf.append("{\n");
398         buf.append("av0 = cw.visitAnnotation(");
399         appendConstant(desc);
400         buf.append(", ");
401         buf.append(visible);
402         buf.append(");\n");
403         text.add(buf.toString());
404         ASMifierAnnotationVisitor av = new ASMifierAnnotationVisitor(0);
405         text.add(av.getText());
406         text.add("}\n");
407         return av;
408     }
409
410     public void visitEnd() {
411         text.add("cw.visitEnd();\n\n");
412         text.add("return cw.toByteArray();\n");
413         text.add("}\n");
414         text.add("}\n");
415         printList(pw, text);
416         pw.flush();
417     }
418
419     // ------------------------------------------------------------------------
420
// Utility methods
421
// ------------------------------------------------------------------------
422

423     /**
424      * Appends a string representation of the given access modifiers to {@link
425      * #buf buf}.
426      *
427      * @param access some access modifiers.
428      */

429     void appendAccess(final int access) {
430         boolean first = true;
431         if ((access & Opcodes.ACC_PUBLIC) != 0) {
432             buf.append("ACC_PUBLIC");
433             first = false;
434         }
435         if ((access & Opcodes.ACC_PRIVATE) != 0) {
436             if (!first) {
437                 buf.append(" + ");
438             }
439             buf.append("ACC_PRIVATE");
440             first = false;
441         }
442         if ((access & Opcodes.ACC_PROTECTED) != 0) {
443             if (!first) {
444                 buf.append(" + ");
445             }
446             buf.append("ACC_PROTECTED");
447             first = false;
448         }
449         if ((access & Opcodes.ACC_FINAL) != 0) {
450             if (!first) {
451                 buf.append(" + ");
452             }
453             buf.append("ACC_FINAL");
454             first = false;
455         }
456         if ((access & Opcodes.ACC_STATIC) != 0) {
457             if (!first) {
458                 buf.append(" + ");
459             }
460             buf.append("ACC_STATIC");
461             first = false;
462         }
463         if ((access & Opcodes.ACC_SYNCHRONIZED) != 0) {
464             if (!first) {
465                 buf.append(" + ");
466             }
467             if ((access & ACCESS_CLASS) != 0) {
468                 buf.append("ACC_SUPER");
469             } else {
470                 buf.append("ACC_SYNCHRONIZED");
471             }
472             first = false;
473         }
474         if ((access & Opcodes.ACC_VOLATILE) != 0
475                 && (access & ACCESS_FIELD) != 0)
476         {
477             if (!first) {
478                 buf.append(" + ");
479             }
480             buf.append("ACC_VOLATILE");
481             first = false;
482         }
483         if ((access & Opcodes.ACC_BRIDGE) != 0 && (access & ACCESS_CLASS) == 0
484                 && (access & ACCESS_FIELD) == 0)
485         {
486             if (!first) {
487                 buf.append(" + ");
488             }
489             buf.append("ACC_BRIDGE");
490             first = false;
491         }
492         if ((access & Opcodes.ACC_VARARGS) != 0 && (access & ACCESS_CLASS) == 0
493                 && (access & ACCESS_FIELD) == 0)
494         {
495             if (!first) {
496                 buf.append(" + ");
497             }
498             buf.append("ACC_VARARGS");
499             first = false;
500         }
501         if ((access & Opcodes.ACC_TRANSIENT) != 0
502                 && (access & ACCESS_FIELD) != 0)
503         {
504             if (!first) {
505                 buf.append(" + ");
506             }
507             buf.append("ACC_TRANSIENT");
508             first = false;
509         }
510         if ((access & Opcodes.ACC_NATIVE) != 0 && (access & ACCESS_CLASS) == 0
511                 && (access & ACCESS_FIELD) == 0)
512         {
513             if (!first) {
514                 buf.append(" + ");
515             }
516             buf.append("ACC_NATIVE");
517             first = false;
518         }
519         if ((access & Opcodes.ACC_ENUM) != 0
520                 && ((access & ACCESS_CLASS) != 0
521                         || (access & ACCESS_FIELD) != 0 || (access & ACCESS_INNER) != 0))
522         {
523             if (!first) {
524                 buf.append(" + ");
525             }
526             buf.append("ACC_ENUM");
527             first = false;
528         }
529         if ((access & Opcodes.ACC_ANNOTATION) != 0
530                 && ((access & ACCESS_CLASS) != 0))
531         {
532             if (!first) {
533                 buf.append(" + ");
534             }
535             buf.append("ACC_ANNOTATION");
536             first = false;
537         }
538         if ((access & Opcodes.ACC_ABSTRACT) != 0) {
539             if (!first) {
540                 buf.append(" + ");
541             }
542             buf.append("ACC_ABSTRACT");
543             first = false;
544         }
545         if ((access & Opcodes.ACC_INTERFACE) != 0) {
546             if (!first) {
547                 buf.append(" + ");
548             }
549             buf.append("ACC_INTERFACE");
550             first = false;
551         }
552         if ((access & Opcodes.ACC_STRICT) != 0) {
553             if (!first) {
554                 buf.append(" + ");
555             }
556             buf.append("ACC_STRICT");
557             first = false;
558         }
559         if ((access & Opcodes.ACC_SYNTHETIC) != 0) {
560             if (!first) {
561                 buf.append(" + ");
562             }
563             buf.append("ACC_SYNTHETIC");
564             first = false;
565         }
566         if ((access & Opcodes.ACC_DEPRECATED) != 0) {
567             if (!first) {
568                 buf.append(" + ");
569             }
570             buf.append("ACC_DEPRECATED");
571             first = false;
572         }
573         if (first) {
574             buf.append("0");
575         }
576     }
577
578     /**
579      * Appends a string representation of the given constant to the given
580      * buffer.
581      *
582      * @param buf a string buffer.
583      * @param cst an {@link java.lang.Integer Integer}, {@link java.lang.Float
584      * Float}, {@link java.lang.Long Long},
585      * {@link java.lang.Double Double} or {@link String String} object.
586      * May be <tt>null</tt>.
587      */

588     static void appendConstant(final StringBuffer JavaDoc buf, final Object JavaDoc cst) {
589         if (cst == null) {
590             buf.append("null");
591         } else if (cst instanceof String JavaDoc) {
592             AbstractVisitor.appendString(buf, (String JavaDoc) cst);
593         } else if (cst instanceof Type) {
594             buf.append("Type.getType(\"")
595                     .append(((Type) cst).getDescriptor())
596                     .append("\")");
597         } else if (cst instanceof Integer JavaDoc) {
598             buf.append("new Integer(").append(cst).append(")");
599         } else if (cst instanceof Float JavaDoc) {
600             buf.append("new Float(\"").append(cst).append("\")");
601         } else if (cst instanceof Long JavaDoc) {
602             buf.append("new Long(").append(cst).append("L)");
603         } else if (cst instanceof Double JavaDoc) {
604             buf.append("new Double(\"").append(cst).append("\")");
605         }
606     }
607 }
608
Popular Tags