KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > cojen > classfile > BuilderStylePrinter


1 /*
2  * Copyright 2004 Brian S O'Neill
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.cojen.classfile;
18
19 import java.io.PrintWriter JavaDoc;
20
21 import org.cojen.classfile.constant.ConstantClassInfo;
22 import org.cojen.classfile.constant.ConstantDoubleInfo;
23 import org.cojen.classfile.constant.ConstantFieldInfo;
24 import org.cojen.classfile.constant.ConstantFloatInfo;
25 import org.cojen.classfile.constant.ConstantIntegerInfo;
26 import org.cojen.classfile.constant.ConstantInterfaceMethodInfo;
27 import org.cojen.classfile.constant.ConstantLongInfo;
28 import org.cojen.classfile.constant.ConstantMethodInfo;
29 import org.cojen.classfile.constant.ConstantNameAndTypeInfo;
30 import org.cojen.classfile.constant.ConstantStringInfo;
31
32 /**
33  * Disassembles a ClassFile into a Java source file, which when run, produces
34  * the original class.
35  *
36  * @author Brian S O'Neill
37  */

38 class BuilderStylePrinter implements DisassemblyTool.Printer {
39     private PrintWriter JavaDoc mOut;
40
41     private int mIndent = 0;
42     private boolean mNeedIndent = true;
43
44     public BuilderStylePrinter() {
45     }
46
47     public void disassemble(ClassFile cf, PrintWriter JavaDoc out) {
48         mOut = out;
49
50         println("import java.io.BufferedOutputStream;");
51         println("import java.io.File;");
52         println("import java.io.FileOutputStream;");
53         println("import java.io.OutputStream;");
54         println();
55         println("import org.cojen.classfile.ClassFile;");
56         println("import org.cojen.classfile.CodeBuilder;");
57         println("import org.cojen.classfile.FieldInfo;");
58         println("import org.cojen.classfile.Label;");
59         println("import org.cojen.classfile.LocalVariable;");
60         println("import org.cojen.classfile.Location;");
61         println("import org.cojen.classfile.MethodInfo;");
62         println("import org.cojen.classfile.Modifiers;");
63         println("import org.cojen.classfile.Opcode;");
64         println("import org.cojen.classfile.TypeDesc;");
65
66         disassemble(cf, (String JavaDoc)null);
67     }
68     
69     private void disassemble(ClassFile cf, String JavaDoc innerClassSuffix) {
70         println();
71         if (innerClassSuffix == null) {
72             println("/**");
73             println(" * Builds ClassFile for " + cf.getClassName());
74             println(" *");
75             println(" * @author auto-generated");
76             println(" */");
77             println("public class ClassFileBuilder {");
78         } else {
79             println("/**");
80             println(" * Builds ClassFile for " + cf.getClassName());
81             println(" */");
82             println("private static class InnerBuilder" + innerClassSuffix + " {");
83         }
84         mIndent += 4;
85
86         if (innerClassSuffix == null) {
87             println("public static void main(String[] args) throws Exception {");
88             mIndent += 4;
89             println("// " + cf);
90             println("ClassFile cf = createClassFile();");
91
92             println();
93             println("if (args.length > 0) {");
94             mIndent += 4;
95             println("File file = new File(args[0]);");
96             println("if (file.isDirectory()) {");
97             mIndent += 4;
98             println("writeClassFiles(cf, file);");
99             mIndent -= 4;
100             println("} else {");
101             mIndent += 4;
102             println("OutputStream out = new BufferedOutputStream(new FileOutputStream(file));");
103             println("cf.writeTo(out);");
104             println("out.close();");
105             mIndent -= 4;
106             println("}");
107             mIndent -= 4;
108             println("}");
109             mIndent -= 4;
110             println("}");
111
112             println();
113             println("private static void writeClassFiles(ClassFile cf, File dir) throws Exception {");
114             mIndent += 4;
115             println("File file = new File(dir, cf.getClassName().replace('.', '/') + \".class\");");
116             println("file.getParentFile().mkdirs();");
117             println("OutputStream out = new BufferedOutputStream(new FileOutputStream(file));");
118             println("cf.writeTo(out);");
119             println("out.close();");
120
121             println();
122             println("ClassFile[] innerClasses = cf.getInnerClasses();");
123             println("for (int i=0; i<innerClasses.length; i++) {");
124             mIndent += 4;
125             println("writeClassFiles(innerClasses[i], dir);");
126             mIndent -= 4;
127             println("}");
128             mIndent -= 4;
129             println("}");
130
131             println();
132         }
133
134         if (innerClassSuffix == null) {
135             println("public static ClassFile createClassFile() {");
136             mIndent += 4;
137             println("ClassFile cf = new ClassFile(\"" + escape(cf.getClassName())
138                     + "\", \"" + escape(cf.getSuperClassName()) + "\");");
139         } else {
140             println("static ClassFile createClassFile(ClassFile cf) {");
141             mIndent += 4;
142         }
143
144         if (cf.getTarget() != null) {
145             println("cf.setTarget(\"" + escape(cf.getTarget()) + "\");");
146         }
147         println("cf.setSourceFile(\"" + escape(cf.getSourceFile()) + "\");");
148
149         if (cf.isSynthetic()) {
150             println("cf.markSynthetic();");
151         }
152         if (cf.isDeprecated()) {
153             println("cf.markDeprecated();");
154         }
155
156         if (!cf.getModifiers().equals(Modifiers.PUBLIC)) {
157             print("cf.setModifiers(");
158             printModifiers(cf);
159             println(");");
160         }
161
162         String JavaDoc[] interfaces = cf.getInterfaces();
163         for (int i=0; i<interfaces.length; i++) {
164             println("cf.addInterface(\"" + escape(interfaces[i]) + "\");");
165         }
166
167         if (cf.getInitializer() != null) {
168             println();
169             println("createStaticInitializer(cf);");
170         }
171
172         FieldInfo[] fields = cf.getFields();
173         boolean createdFieldVariable = false;
174
175         for (int i=0; i<fields.length; i++) {
176             if (i == 0) {
177                 println();
178                 println("//");
179                 println("// Create fields");
180                 println("//");
181             }
182
183             println();
184
185             FieldInfo fi = fields[i];
186             if (fi.isSynthetic() || fi.isDeprecated() || fi.getConstantValue() != null) {
187                 if (!createdFieldVariable) {
188                     print("FieldInfo ");
189                     createdFieldVariable = true;
190                 }
191                 print("fi = ");
192             }
193
194             print("cf.addField(");
195             printModifiers(fi);
196             print(", ");
197             print('\"' + escape(fi.getName()) + "\", ");
198             print(fi.getType());
199             println(");");
200
201             if (fi.getConstantValue() != null) {
202                 ConstantInfo constant = fi.getConstantValue();
203                 print("fi.setConstantValue(");
204                 if (constant instanceof ConstantStringInfo) {
205                     print("\"");
206                     String JavaDoc value = ((ConstantStringInfo)constant).getValue();
207                     print(escape(value));
208                     print("\"");
209                 } else if (constant instanceof ConstantIntegerInfo) {
210                     print(String.valueOf(((ConstantIntegerInfo)constant).getValue()));
211                 } else if (constant instanceof ConstantLongInfo) {
212                     print(String.valueOf(((ConstantLongInfo)constant).getValue()));
213                     print("L");
214                 } else if (constant instanceof ConstantFloatInfo) {
215                     float value = ((ConstantFloatInfo)constant).getValue();
216                     if (value != value) {
217                         print("0.0f/0.0f");
218                     } else if (value == Float.NEGATIVE_INFINITY) {
219                         print("-1.0f/0.0f");
220                     } else if (value == Float.POSITIVE_INFINITY) {
221                         print("1.0f/0.0f");
222                     } else {
223                         print(String.valueOf(value));
224                         print("f");
225                     }
226                 } else if (constant instanceof ConstantDoubleInfo) {
227                     double value = ((ConstantDoubleInfo)constant).getValue();
228                     if (value != value) {
229                         print("0.0d/0.0d");
230                     } else if (value == Float.NEGATIVE_INFINITY) {
231                         print("-1.0d/0.0d");
232                     } else if (value == Float.POSITIVE_INFINITY) {
233                         print("1.0d/0.0d");
234                     } else {
235                         print(String.valueOf(value));
236                         print("d");
237                     }
238                 }
239                 println(");");
240             }
241             if (fi.isSynthetic()) {
242                 println("fi.markSynthetic();");
243             }
244             if (fi.isDeprecated()) {
245                 println("fi.markDeprecated();");
246             }
247         }
248
249         MethodInfo[] methods = cf.getConstructors();
250         for (int i=0; i<methods.length; i++) {
251             if (i == 0) {
252                 println();
253                 println("//");
254                 println("// Create constructors");
255                 println("//");
256             }
257             println();
258             println("// " + methods[i]);
259             println("createConstructor_" + (i + 1) + "(cf);");
260         }
261
262         methods = cf.getMethods();
263         for (int i=0; i<methods.length; i++) {
264             if (i == 0) {
265                 println();
266                 println("//");
267                 println("// Create methods");
268                 println("//");
269             }
270
271             println();
272             println("// " + methods[i]);
273             println("createMethod_" + (i + 1) + "(cf);");
274         }
275
276         final ClassFile[] innerClasses = cf.getInnerClasses();
277
278         for (int i=0; i<innerClasses.length; i++) {
279             if (i == 0) {
280                 println();
281                 println("//");
282                 println("// Create inner classes");
283                 println("//");
284             }
285
286             println();
287             println("// " + innerClasses[i]);
288             
289             if (i == 0) {
290                 print("ClassFile ");
291             }
292             print("innerClass = ");
293             String JavaDoc name = innerClasses[i].getClassName();
294             String JavaDoc innerName = innerClasses[i].getInnerClassName();
295             if (innerName != null) {
296                 if ((cf.getClassName() + '$' + innerName).equals(name)) {
297                     name = null;
298                 }
299                 innerName = '"' + escape(innerName) + '"';
300             }
301             if (name != null) {
302                 name = '"' + escape(name) + '"';
303             }
304             println("cf.addInnerClass(" + name + ", " + innerName + ", \"" +
305                     escape(innerClasses[i].getSuperClassName()) + "\");");
306             String JavaDoc suffix = "_" + (i + 1);
307             if (innerClassSuffix != null) {
308                 suffix = innerClassSuffix + suffix;
309             }
310             println("InnerBuilder" + suffix + ".createClassFile(innerClass);");
311         }
312
313         println();
314         println("return cf;");
315
316         mIndent -= 4;
317         println("}");
318
319         if (cf.getInitializer() != null) {
320             println();
321             println("private static void createStaticInitializer(ClassFile cf) {");
322             mIndent += 4;
323             disassemble(cf.getInitializer());
324             mIndent -= 4;
325             println("}");
326         }
327
328         methods = cf.getConstructors();
329         for (int i=0; i<methods.length; i++) {
330             println();
331             println("// " + methods[i]);
332             println("private static void createConstructor_" + (i + 1) + "(ClassFile cf) {");
333             mIndent += 4;
334             disassemble(methods[i]);
335             mIndent -= 4;
336             println("}");
337         }
338
339         methods = cf.getMethods();
340         for (int i=0; i<methods.length; i++) {
341             println();
342             println("// " + methods[i]);
343             println("private static void createMethod_" + (i + 1) + "(ClassFile cf) {");
344             mIndent += 4;
345             disassemble(methods[i]);
346             mIndent -= 4;
347             println("}");
348         }
349
350         for (int i=0; i<innerClasses.length; i++) {
351             String JavaDoc suffix = "_" + (i + 1);
352             if (innerClassSuffix != null) {
353                 suffix = innerClassSuffix + suffix;
354             }
355             disassemble(innerClasses[i], suffix);
356         }
357
358         mIndent -= 4;
359         println("}");
360     }
361
362     private void disassemble(MethodInfo mi) {
363         print("MethodInfo mi = cf.add");
364
365         if (mi.getName().equals("<clinit>")) {
366             println("Initializer();");
367         } else if (mi.getName().equals("<init>")) {
368             print("Constructor(");
369             printModifiers(mi);
370             print(", ");
371             print(mi.getMethodDescriptor().getParameterTypes());
372             println(");");
373         } else {
374             print("Method(");
375             printModifiers(mi);
376             print(", ");
377             print("\"" + escape(mi.getName()) + "\", ");
378             print(mi.getMethodDescriptor().getReturnType());
379             print(", ");
380             print(mi.getMethodDescriptor().getParameterTypes());
381             println(");");
382         }
383
384         if (mi.isSynthetic()) {
385             println("mi.markSynthetic();");
386         }
387         if (mi.isDeprecated()) {
388             println("mi.markDeprecated();");
389         }
390         TypeDesc[] exceptions = mi.getExceptions();
391         for (int j=0; j<exceptions.length; j++) {
392             print("mi.addException(");
393             print(exceptions[j]);
394             println(");");
395         }
396
397         if (mi.getCodeAttr() != null) {
398             println("CodeBuilder b = new CodeBuilder(mi);");
399             println();
400
401             TypeDesc[] paramTypes = mi.getMethodDescriptor().getParameterTypes();
402             boolean isStatic = mi.getModifiers().isStatic();
403             String JavaDoc indentStr = generateIndent(mIndent);
404             
405             new CodeDisassembler(mi).disassemble
406                 (new CodeAssemblerPrinter(paramTypes, isStatic,
407                                           mOut, indentStr, ";", "b."));
408         }
409     }
410
411     private String JavaDoc escape(String JavaDoc str) {
412         return CodeAssemblerPrinter.escape(str);
413     }
414
415     private void printModifiers(ClassFile cf) {
416         printModifiers(cf.getModifiers());
417     }
418
419     private void printModifiers(FieldInfo fi) {
420         printModifiers(fi.getModifiers());
421     }
422
423     private void printModifiers(MethodInfo mi) {
424         printModifiers(mi.getModifiers());
425     }
426
427     private void printModifiers(Modifiers modifiers) {
428         print("Modifiers.");
429
430         if (modifiers.isPublic()) {
431             if (modifiers.isAbstract()) {
432                 print("PUBLIC_ABSTRACT");
433                 modifiers = modifiers.toAbstract(false);
434             } else if (modifiers.isStatic()) {
435                 print("PUBLIC_STATIC");
436                 modifiers = modifiers.toStatic(false);
437             } else {
438                 print("PUBLIC");
439             }
440             modifiers = modifiers.toPublic(false);
441         } else if (modifiers.isProtected()) {
442             print("PROTECTED");
443             modifiers = modifiers.toProtected(false);
444         } else if (modifiers.isPrivate()) {
445             print("PRIVATE");
446             modifiers = modifiers.toPrivate(false);
447         } else {
448             print("NONE");
449         }
450
451         if (modifiers.isStatic()) {
452             print(".toStatic(true)");
453         }
454         if (modifiers.isFinal()) {
455             print(".toFinal(true)");
456         }
457         if (modifiers.isSynchronized()) {
458             print(".toSynchronized(true)");
459         }
460         if (modifiers.isVolatile()) {
461             print(".toVolatile(true)");
462         }
463         if (modifiers.isTransient()) {
464             print(".toTransient(true)");
465         }
466         if (modifiers.isNative()) {
467             print(".toNative(true)");
468         }
469         if (modifiers.isInterface()) {
470             print(".toInterface(true)");
471         }
472         if (modifiers.isAbstract() && !modifiers.isInterface()) {
473             print(".toAbstract(true)");
474         }
475         if (modifiers.isStrict()) {
476             print(".toStrict(true)");
477         }
478     }
479
480     private void print(TypeDesc type) {
481         if (type == null || type == TypeDesc.VOID) {
482             print("null");
483             return;
484         }
485
486         if (type.isPrimitive()) {
487             print("TypeDesc.".concat(type.getFullName().toUpperCase()));
488             return;
489         } else if (type == TypeDesc.OBJECT) {
490             print("TypeDesc.OBJECT");
491             return;
492         } else if (type == TypeDesc.STRING) {
493             print("TypeDesc.STRING");
494             return;
495         }
496
497         TypeDesc componentType = type.getComponentType();
498         if (componentType != null) {
499             print(componentType);
500             print(".toArrayType()");
501         } else {
502             print("TypeDesc.forClass(\"");
503             print(escape(type.getRootName()));
504             print("\")");
505         }
506     }
507
508     private void print(TypeDesc[] params) {
509         if (params == null || params.length == 0) {
510             print("null");
511             return;
512         }
513
514         print("new TypeDesc[] {");
515
516         for (int i=0; i<params.length; i++) {
517             if (i > 0) {
518                 print(", ");
519             }
520             print(params[i]);
521         }
522
523         print("}");
524     }
525
526     private void print(String JavaDoc text) {
527         indent();
528         mOut.print(text);
529     }
530
531     private void println(String JavaDoc text) {
532         print(text);
533         println();
534     }
535
536     private void println() {
537         mOut.println();
538         mNeedIndent = true;
539     }
540
541     private void indent() {
542         if (mNeedIndent) {
543             for (int i=mIndent; --i>= 0; ) {
544                 mOut.print(' ');
545             }
546             mNeedIndent = false;
547         }
548     }
549
550     private String JavaDoc generateIndent(int amount) {
551         StringBuffer JavaDoc buf = new StringBuffer JavaDoc(amount);
552         for (int i=0; i<amount; i++) {
553             buf.append(' ');
554         }
555         return buf.toString();
556     }
557 }
558
Popular Tags