KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > oracle > toplink > libraries > asm > util > ASMifierClassVisitor


1 /***
2  * ASM: a very small and fast Java bytecode manipulation framework
3  * Copyright (c) 2000,2002,2003 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
31 package oracle.toplink.libraries.asm.util;
32
33 import java.io.FileInputStream JavaDoc;
34 import java.io.PrintWriter JavaDoc;
35
36 import oracle.toplink.libraries.asm.Attribute;
37 import oracle.toplink.libraries.asm.ClassReader;
38 import oracle.toplink.libraries.asm.CodeVisitor;
39 import oracle.toplink.libraries.asm.Constants;
40 import oracle.toplink.libraries.asm.Type;
41 import oracle.toplink.libraries.asm.util.attrs.ASMifiable;
42
43 /**
44  * A {@link PrintClassVisitor PrintClassVisitor} that prints the ASM code that
45  * generates the classes it visits. This class visitor can be used to quickly
46  * write ASM code to generate some given bytecode:
47  * <ul>
48  * <li>write the Java source code equivalent to the bytecode you want to
49  * generate;</li>
50  * <li>compile it with <tt>javac</tt>;</li>
51  * <li>make a {@link ASMifierClassVisitor} visit this compiled
52  * class (see the {@link #main main} method);</li>
53  * <li>edit the generated source code, if necessary.</li>
54  * </ul>
55  * The source code printed when visiting the <tt>Hello</tt> class is the
56  * following:
57  * <p>
58  * <blockquote>
59  * <pre>
60  * import oracle.toplink.libraries.asm.*;
61  * import java.io.FileOutputStream;
62  *
63  * public class Dump implements Constants {
64  *
65  * public static void main (String[] args) throws Exception {
66  *
67  * ClassWriter cw = new ClassWriter(false);
68  * CodeVisitor cv;
69  *
70  * cw.visit(ACC_PUBLIC + ACC_SUPER, "Hello", "java/lang/Object", null, "Hello.java");
71  *
72  * {
73  * cv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);
74  * cv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
75  * cv.visitLdcInsn("hello");
76  * cv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V");
77  * cv.visitInsn(RETURN);
78  * cv.visitMaxs(2, 1);
79  * }
80  * {
81  * cv = cw.visitMethod(ACC_PUBLIC, "&lt;init&gt;", "()V", null, null);
82  * cv.visitVarInsn(ALOAD, 0);
83  * cv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "&lt;init&gt;", "()V");
84  * cv.visitInsn(RETURN);
85  * cv.visitMaxs(1, 1);
86  * }
87  * cw.visitEnd();
88  *
89  * FileOutputStream os = new FileOutputStream("Dumped.class");
90  * os.write(cw.toByteArray());
91  * os.close();
92  * }
93  * }
94  * </pre>
95  * </blockquote>
96  * where <tt>Hello</tt> is defined by:
97  * <p>
98  * <blockquote>
99  * <pre>
100  * public class Hello {
101  *
102  * public static void main (String[] args) {
103  * System.out.println("hello");
104  * }
105  * }
106  * </pre>
107  * </blockquote>
108  *
109  * @author Eric Bruneton, Eugene Kuleshov
110  */

111
112 public class ASMifierClassVisitor extends PrintClassVisitor {
113
114   private static final int ACCESS_CLASS = 262144;
115   private static final int ACCESS_FIELD = 524288;
116   private static final int ACCESS_INNER = 1048576;
117
118   /**
119    * Prints the ASM source code to generate the given class to the standard
120    * output.
121    * <p>
122    * Usage: ASMifierClassVisitor [-debug]
123    * &lt;fully qualified class name or class file name&gt;
124    *
125    * @param args the command line arguments.
126    *
127    * @throws Exception if the class cannot be found, or if an IO exception
128    * occurs.
129    */

130
131   public static void main (final String JavaDoc[] args) throws Exception JavaDoc {
132     if (args.length < 1 || args.length > 2) {
133       printUsage();
134     }
135     int i = 0;
136     boolean skipDebug = true;
137     if (args[0].equals("-debug")) {
138       i = 1;
139       skipDebug = false;
140       if (args.length != 2) {
141         printUsage();
142       }
143     }
144     ClassReader cr;
145     if (args[i].endsWith(".class")) {
146       cr = new ClassReader(new FileInputStream JavaDoc(args[i]));
147     } else {
148       cr = new ClassReader(args[i]);
149     }
150     cr.accept(new ASMifierClassVisitor(
151       new PrintWriter JavaDoc(System.out)), getDefaultAttributes(), skipDebug);
152   }
153
154   private static void printUsage () {
155     System.err.println("Prints the ASM code to generate the given class.");
156     System.err.println("Usage: ASMifierClassVisitor [-debug] " +
157                        "<fully qualified class name or class file name>");
158     System.exit(-1);
159   }
160
161   /**
162    * Constructs a new {@link ASMifierClassVisitor} object.
163    *
164    * @param pw the print writer to be used to print the class.
165    */

166
167   public ASMifierClassVisitor (final PrintWriter JavaDoc pw) {
168     super(pw);
169   }
170
171   public void visit (
172     final int version,
173     final int access,
174     final String JavaDoc name,
175     final String JavaDoc superName,
176     final String JavaDoc[] interfaces,
177     final String JavaDoc sourceFile)
178   {
179     int n = name.lastIndexOf( "/");
180     if( n>-1) {
181       text.add("package asm."+name.substring( 0, n).replace( '/', '.')+";\n");
182     }
183     
184     text.add("import oracle.toplink.libraries.asm.*;\n");
185     text.add("import oracle.toplink.libraries.asm.attrs.*;\n");
186     text.add("import java.util.*;\n\n");
187     text.add("public class "+(n==-1 ? name : name.substring( n+1))+"Dump implements Constants {\n\n");
188     text.add("public static byte[] dump () throws Exception {\n\n");
189     text.add("ClassWriter cw = new ClassWriter(false);\n");
190     text.add("CodeVisitor cv;\n\n");
191
192     buf.setLength(0);
193     buf.append("cw.visit(");
194     switch(version) {
195       case Constants.V1_1:
196         buf.append("V1_1");
197         break;
198       
199       case Constants.V1_2:
200         buf.append("V1_2");
201         break;
202       
203       case Constants.V1_3:
204         buf.append("V1_3");
205         break;
206       
207       case Constants.V1_4:
208         buf.append("V1_4");
209         break;
210       
211       case Constants.V1_5:
212         buf.append("V1_5");
213         break;
214   
215       default:
216         buf.append(version);
217         break;
218     }
219     buf.append(", ");
220     appendAccess(access | ACCESS_CLASS);
221     buf.append(", ");
222     appendConstant(buf, name);
223     buf.append(", ");
224     appendConstant(buf, superName);
225     buf.append(", ");
226     if (interfaces != null && interfaces.length > 0) {
227       buf.append("new String[] {");
228       for (int i = 0; i < interfaces.length; ++i) {
229         buf.append(i == 0 ? " " : ", ");
230         appendConstant(buf, interfaces[i]);
231       }
232       buf.append(" }");
233     } else {
234       buf.append("null");
235     }
236     buf.append(", ");
237     appendConstant(buf, sourceFile);
238     buf.append(");\n\n");
239     text.add(buf.toString());
240   }
241
242   public void visitInnerClass (
243     final String JavaDoc name,
244     final String JavaDoc outerName,
245     final String JavaDoc innerName,
246     final int access)
247   {
248     buf.setLength(0);
249     buf.append("cw.visitInnerClass(");
250     appendConstant(buf, name);
251     buf.append(", ");
252     appendConstant(buf, outerName);
253     buf.append(", ");
254     appendConstant(buf, innerName);
255     buf.append(", ");
256     appendAccess(access | ACCESS_INNER);
257     buf.append(");\n\n");
258     text.add(buf.toString());
259   }
260
261   public void visitField (
262     final int access,
263     final String JavaDoc name,
264     final String JavaDoc desc,
265     final Object JavaDoc value,
266     final Attribute attrs)
267   {
268     buf.setLength(0);
269
270     int n = 1;
271     if (attrs != null) {
272       buf.append("{\n");
273       buf.append("// FIELD ATTRIBUTES\n");
274       Attribute a = attrs;
275       while (a != null) {
276         if (a instanceof ASMifiable) {
277           ((ASMifiable)a).asmify(buf, "fieldAttrs" + n, null);
278           if (n > 1) {
279             buf.append("fieldAttrs" + (n - 1) + " = fieldAttrs" + n + ";\n");
280           }
281           n++;
282         } else {
283           buf.append("// WARNING! skipped non standard field attribute of type ");
284           buf.append(a.type).append("\n");
285         }
286         a = a.next;
287       }
288     }
289
290     buf.append("cw.visitField(");
291     appendAccess(access | ACCESS_FIELD);
292     buf.append(", ");
293     appendConstant(buf, name);
294     buf.append(", ");
295     appendConstant(buf, desc);
296     buf.append(", ");
297     appendConstant(buf, value);
298
299     if (n==1) {
300       buf.append(", null);\n\n");
301     } else {
302       buf.append(", fieldAttrs1);\n");
303       buf.append("}\n\n");
304     }
305
306     text.add(buf.toString());
307   }
308
309   public CodeVisitor visitMethod (
310     final int access,
311     final String JavaDoc name,
312     final String JavaDoc desc,
313     final String JavaDoc[] exceptions,
314     final Attribute attrs)
315   {
316     buf.setLength(0);
317
318     buf.append("{\n");
319
320     int n = 1;
321     if (attrs != null) {
322       buf.append("// METHOD ATTRIBUTES\n");
323       Attribute a = attrs;
324       while (a != null) {
325         if (a instanceof ASMifiable) {
326           ((ASMifiable)a).asmify(buf, "methodAttrs" + n, null);
327           if (n > 1) {
328             buf.append("methodAttrs" + (n - 1) + ".next = methodAttrs" + n + ";\n");
329           }
330           n++;
331         } else {
332           buf.append("// WARNING! skipped non standard method attribute of type ");
333           buf.append(a.type).append("\n");
334         }
335         a = a.next;
336       }
337     }
338
339     buf.append("cv = cw.visitMethod(");
340     appendAccess(access);
341     buf.append(", ");
342     appendConstant(buf, name);
343     buf.append(", ");
344     appendConstant(buf, desc);
345     buf.append(", ");
346     if (exceptions != null && exceptions.length > 0) {
347       buf.append("new String[] {");
348       for (int i = 0; i < exceptions.length; ++i) {
349         buf.append(i == 0 ? " " : ", ");
350         appendConstant(buf, exceptions[i]);
351       }
352       buf.append(" }");
353     } else {
354       buf.append("null");
355     }
356     if (n==1) {
357       buf.append(", null);\n");
358     } else {
359       buf.append(", methodAttrs1);\n");
360     }
361
362     text.add(buf.toString());
363     PrintCodeVisitor pcv = new ASMifierCodeVisitor();
364     text.add(pcv.getText());
365     text.add("}\n");
366     return pcv;
367   }
368
369   public void visitAttribute (final Attribute attr) {
370     buf.setLength(0);
371     if (attr instanceof ASMifiable) {
372       buf.append("{\n");
373       buf.append("// CLASS ATRIBUTE\n");
374       ((ASMifiable)attr).asmify(buf, "attr", null);
375       buf.append("cw.visitAttribute(attr);\n");
376       buf.append("}\n");
377     } else {
378       buf.append("// WARNING! skipped a non standard class attribute of type \"");
379       buf.append(attr.type).append("\"\n");
380     }
381     text.add(buf.toString());
382   }
383
384   public void visitEnd () {
385     text.add("cw.visitEnd();\n\n");
386     // text.add("FileOutputStream os = new FileOutputStream(\"Dumped.class\");\n");
387
// text.add("os.write(cw.toByteArray());\n");
388
// text.add("os.close();\n");
389
text.add("return cw.toByteArray();\n");
390     text.add("}\n");
391     text.add("}\n");
392     super.visitEnd();
393   }
394
395   /**
396    * Appends a string representation of the given access modifiers to {@link
397    * #buf buf}.
398    *
399    * @param access some access modifiers.
400    */

401
402   void appendAccess (final int access) {
403     boolean first = true;
404     if ((access & Constants.ACC_PUBLIC) != 0) {
405       buf.append("ACC_PUBLIC");
406       first = false;
407     }
408     if ((access & Constants.ACC_PRIVATE) != 0) {
409       if (!first) {
410         buf.append(" + ");
411       }
412       buf.append("ACC_PRIVATE");
413       first = false;
414     }
415     if ((access & Constants.ACC_PROTECTED) != 0) {
416       if (!first) {
417         buf.append(" + ");
418       }
419       buf.append("ACC_PROTECTED");
420       first = false;
421     }
422     if ((access & Constants.ACC_FINAL) != 0) {
423       if (!first) {
424         buf.append(" + ");
425       }
426       buf.append("ACC_FINAL");
427       first = false;
428     }
429     if ((access & Constants.ACC_STATIC) != 0) {
430       if (!first) {
431         buf.append(" + ");
432       }
433       buf.append("ACC_STATIC");
434       first = false;
435     }
436     if ((access & Constants.ACC_SYNCHRONIZED) != 0) {
437       if (!first) {
438         buf.append(" + ");
439       }
440       if ((access & ACCESS_CLASS) != 0) {
441         buf.append("ACC_SUPER");
442       } else {
443         buf.append("ACC_SYNCHRONIZED");
444       }
445       first = false;
446     }
447     if ((access & Constants.ACC_VOLATILE) != 0 && (access & ACCESS_FIELD) != 0 ) {
448       if (!first) {
449         buf.append(" + ");
450       }
451       buf.append("ACC_VOLATILE");
452       first = false;
453     }
454     if ((access & Constants.ACC_BRIDGE) != 0 &&
455         (access & ACCESS_CLASS) == 0 && (access & ACCESS_FIELD) == 0) {
456       if (!first) {
457         buf.append(" + ");
458       }
459       buf.append("ACC_BRIDGE");
460       first = false;
461     }
462     if ((access & Constants.ACC_VARARGS) != 0 &&
463         (access & ACCESS_CLASS) == 0 && (access & ACCESS_FIELD) == 0) {
464       if (!first) {
465         buf.append(" + ");
466       }
467       buf.append("ACC_VARARGS");
468       first = false;
469     }
470     if ((access & Constants.ACC_TRANSIENT) != 0 &&
471         (access & ACCESS_FIELD) != 0) {
472       if (!first) {
473         buf.append(" + ");
474       }
475       buf.append("ACC_TRANSIENT");
476       first = false;
477     }
478     if ((access & Constants.ACC_NATIVE) != 0 &&
479         (access & ACCESS_CLASS) == 0 &&
480         (access & ACCESS_FIELD) == 0) {
481       if (!first) {
482         buf.append(" + ");
483       }
484       buf.append("ACC_NATIVE");
485       first = false;
486     }
487     if ((access & Constants.ACC_ENUM) != 0 &&
488          ((access & ACCESS_CLASS) != 0 ||
489           (access & ACCESS_FIELD) != 0 ||
490           (access & ACCESS_INNER) != 0)) {
491       if (!first) {
492         buf.append(" + ");
493       }
494       buf.append("ACC_ENUM");
495       first = false;
496     }
497     if ((access & Constants.ACC_ANNOTATION) != 0 &&
498         ((access & ACCESS_CLASS) != 0)) {
499       if (!first) {
500         buf.append(" + ");
501       }
502       buf.append("ACC_ANNOTATION");
503       first = false;
504     }
505     if ((access & Constants.ACC_ABSTRACT) != 0) {
506       if (!first) {
507         buf.append(" + ");
508       }
509       buf.append("ACC_ABSTRACT");
510       first = false;
511     }
512     if ((access & Constants.ACC_INTERFACE) != 0) {
513       if (!first) {
514         buf.append(" + ");
515       }
516       buf.append("ACC_INTERFACE");
517       first = false;
518     }
519     if ((access & Constants.ACC_STRICT) != 0) {
520       if (!first) {
521         buf.append(" + ");
522       }
523       buf.append("ACC_STRICT");
524       first = false;
525     }
526     if ((access & Constants.ACC_SYNTHETIC) != 0) {
527       if (!first) {
528         buf.append(" + ");
529       }
530       buf.append("ACC_SYNTHETIC");
531       first = false;
532     }
533     if ((access & Constants.ACC_DEPRECATED) != 0) {
534       if (!first) {
535         buf.append(" + ");
536       }
537       buf.append("ACC_DEPRECATED");
538       first = false;
539     }
540     if (first) {
541       buf.append("0");
542     }
543   }
544
545   /**
546    * Appends a string representation of the given constant to the given buffer.
547    *
548    * @param buf a string buffer.
549    * @param cst an {@link java.lang.Integer Integer}, {@link java.lang.Float
550    * Float}, {@link java.lang.Long Long}, {@link java.lang.Double Double}
551    * or {@link String String} object. May be <tt>null</tt>.
552    */

553
554   static void appendConstant (final StringBuffer JavaDoc buf, final Object JavaDoc cst) {
555     if (cst == null) {
556       buf.append("null");
557     } else if (cst instanceof String JavaDoc) {
558       String JavaDoc s = (String JavaDoc)cst;
559       buf.append("\"");
560       for (int i = 0; i < s.length(); ++i) {
561         char c = s.charAt(i);
562         if (c == '\n') {
563           buf.append("\\n");
564         } else if (c == '\r') {
565             buf.append("\\r");
566         } else if (c == '\\') {
567           buf.append("\\\\");
568         } else if (c == '"') {
569           buf.append("\\\"");
570         } else if( c<0x20 || c>0x7f) {
571           buf.append( "\\u");
572           if( c<0x10) {
573             buf.append( "000");
574           } else if( c<0x100) {
575             buf.append( "00");
576           } else if( c<0x1000) {
577             buf.append( "0");
578           }
579           buf.append( Integer.toString( c, 16));
580         } else {
581           buf.append(c);
582         }
583       }
584       buf.append("\"");
585     } else if (cst instanceof Type) {
586       buf.append("Type.getType(\"");
587       buf.append(((Type)cst).getDescriptor());
588       buf.append("\")");
589     } else if (cst instanceof Integer JavaDoc) {
590       buf.append("new Integer(")
591         .append(cst)
592         .append(")");
593     } else if (cst instanceof Float JavaDoc) {
594       buf.append("new Float(\"")
595         .append(cst).append("\")");
596     } else if (cst instanceof Long JavaDoc) {
597       buf.append("new Long(")
598         .append(cst)
599         .append("L)");
600     } else if (cst instanceof Double JavaDoc) {
601       buf.append("new Double(\"")
602         .append(cst).append("\")");
603     }
604   }
605 }
606
Popular Tags