KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > 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 org.objectweb.asm.util;
31
32 import java.io.FileInputStream JavaDoc;
33 import java.io.PrintWriter JavaDoc;
34
35 import org.objectweb.asm.AnnotationVisitor;
36 import org.objectweb.asm.ClassReader;
37 import org.objectweb.asm.ClassVisitor;
38 import org.objectweb.asm.FieldVisitor;
39 import org.objectweb.asm.MethodVisitor;
40 import org.objectweb.asm.Opcodes;
41 import org.objectweb.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             System.exit(-1);
182         }
183         ClassReader cr;
184         if (args[i].endsWith(".class")) {
185             cr = new ClassReader(new FileInputStream JavaDoc(args[i]));
186         } else {
187             cr = new ClassReader(args[i]);
188         }
189         cr.accept(new ASMifierClassVisitor(new PrintWriter JavaDoc(System.out)),
190                 getDefaultAttributes(),
191                 skipDebug);
192     }
193
194     /**
195      * Constructs a new {@link ASMifierClassVisitor} object.
196      *
197      * @param pw the print writer to be used to print the class.
198      */

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

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

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

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

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