src/share/classes/com/sun/tools/javap/ClassWriter.java

changeset 46
7708bd6d800d
child 52
3cb4fb6e0720
equal deleted inserted replaced
42:f7e64b33d5a4 46:7708bd6d800d
1 /*
2 * Copyright 2007 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26 package com.sun.tools.javap;
27
28 import java.util.Collection;
29 import java.util.List;
30
31 import com.sun.tools.classfile.AccessFlags;
32 import com.sun.tools.classfile.Attribute;
33 import com.sun.tools.classfile.Attributes;
34 import com.sun.tools.classfile.ClassFile;
35 import com.sun.tools.classfile.Code_attribute;
36 import com.sun.tools.classfile.ConstantPool;
37 import com.sun.tools.classfile.ConstantPoolException;
38 import com.sun.tools.classfile.Descriptor;
39 import com.sun.tools.classfile.DescriptorException;
40 import com.sun.tools.classfile.Exceptions_attribute;
41 import com.sun.tools.classfile.Field;
42 import com.sun.tools.classfile.Method;
43 import com.sun.tools.classfile.Signature;
44 import com.sun.tools.classfile.Signature_attribute;
45 import com.sun.tools.classfile.SourceFile_attribute;
46 import com.sun.tools.classfile.Type;
47
48 import static com.sun.tools.classfile.AccessFlags.*;
49
50 /*
51 * The main javap class to write the contents of a class file as text.
52 *
53 * <p><b>This is NOT part of any API supported by Sun Microsystems. If
54 * you write code that depends on this, you do so at your own risk.
55 * This code and its internal interfaces are subject to change or
56 * deletion without notice.</b>
57 */
58 public class ClassWriter extends BasicWriter {
59 static ClassWriter instance(Context context) {
60 ClassWriter instance = context.get(ClassWriter.class);
61 if (instance == null)
62 instance = new ClassWriter(context);
63 return instance;
64 }
65
66 protected ClassWriter(Context context) {
67 super(context);
68 context.put(ClassWriter.class, this);
69 options = Options.instance(context);
70 attrWriter = AttributeWriter.instance(context);
71 codeWriter = CodeWriter.instance(context);
72 constantWriter = ConstantWriter.instance(context);
73 }
74
75 ClassFile getClassFile() {
76 return classFile;
77 }
78
79 Method getMethod() {
80 return method;
81 }
82
83 public void write(ClassFile cf) {
84 classFile = cf;
85 constant_pool = classFile.constant_pool;
86
87 Attribute sfa = cf.getAttribute(Attribute.SourceFile);
88 if (sfa instanceof SourceFile_attribute) {
89 println("Compiled from \"" + getSourceFile((SourceFile_attribute) sfa) + "\"");
90 }
91
92 String name = getJavaName(classFile);
93 AccessFlags flags = cf.access_flags;
94
95 writeModifiers(flags.getClassModifiers());
96
97 if (classFile.isClass())
98 print("class ");
99 else if (classFile.isInterface())
100 print("interface ");
101
102 print(name);
103
104 Signature_attribute sigAttr = getSignature(cf.attributes);
105 if (sigAttr == null) {
106 // use info from class file header
107 if (classFile.isClass()) {
108 if (classFile.super_class != 0 ) {
109 String sn = getJavaSuperclassName(cf);
110 if (!sn.equals("java.lang.Object") || options.compat) { // BUG XXXXXXXX
111 print(" extends ");
112 print(sn);
113 }
114 }
115 }
116 for (int i = 0; i < classFile.interfaces.length; i++) {
117 print(i == 0 ? (classFile.isClass() ? " implements " : " extends ") : ",");
118 print(getJavaInterfaceName(classFile, i));
119 }
120 } else {
121 try {
122 Type t = sigAttr.getParsedSignature().getType(constant_pool);
123 // The signature parser cannot disambiguate between a
124 // FieldType and a ClassSignatureType that only contains a superclass type.
125 if (t instanceof Type.ClassSigType)
126 print(t);
127 else if (!t.isObject()) {
128 print(" extends ");
129 print(t);
130 }
131 } catch (ConstantPoolException e) {
132 print(report(e));
133 }
134 }
135
136 if (options.verbose) {
137 println();
138 attrWriter.write(cf, cf.attributes, constant_pool);
139 println(" minor version: " + cf.minor_version);
140 println(" major version: " + cf.major_version);
141 if (!options.compat)
142 writeList(" flags: ", flags.getClassFlags(), NEWLINE);
143 constantWriter.writeConstantPool();
144 println();
145 } else {
146 if (!options.compat)
147 print(" ");
148 }
149
150 println("{");
151 writeFields();
152 writeMethods();
153 println("}");
154 println();
155 }
156
157 void writeFields() {
158 for (Field f: classFile.fields) {
159 writeField(f);
160 }
161 }
162
163 void writeField(Field f) {
164 if (!options.checkAccess(f.access_flags))
165 return;
166
167 if (!(options.showLineAndLocalVariableTables
168 || options.showDisassembled
169 || options.verbose
170 || options.showInternalSignatures
171 || options.showAllAttrs)) {
172 print(" ");
173 }
174
175 AccessFlags flags = f.access_flags;
176 writeModifiers(flags.getFieldModifiers());
177 Signature_attribute sigAttr = getSignature(f.attributes);
178 if (sigAttr == null)
179 print(getFieldType(f.descriptor));
180 else {
181 try {
182 Type t = sigAttr.getParsedSignature().getType(constant_pool);
183 print(t);
184 } catch (ConstantPoolException e) {
185 // report error?
186 // fall back on non-generic descriptor
187 print(getFieldType(f.descriptor));
188 }
189 }
190 print(" ");
191 print(getFieldName(f));
192 print(";");
193 println();
194
195 if (options.showInternalSignatures)
196 println(" Signature: " + getValue(f.descriptor));
197
198 if (options.verbose && !options.compat)
199 writeList(" flags: ", flags.getFieldFlags(), NEWLINE);
200
201 if (options.showAllAttrs) {
202 for (Attribute attr: f.attributes)
203 attrWriter.write(f, attr, constant_pool);
204 println();
205 }
206
207 if (options.showDisassembled || options.showLineAndLocalVariableTables)
208 println();
209 }
210
211 void writeMethods() {
212 for (Method m: classFile.methods)
213 writeMethod(m);
214 }
215
216 void writeMethod(Method m) {
217 if (!options.checkAccess(m.access_flags))
218 return;
219
220 method = m;
221
222 if (!(options.showLineAndLocalVariableTables
223 || options.showDisassembled
224 || options.verbose
225 || options.showInternalSignatures
226 || options.showAllAttrs)) {
227 print(" ");
228 }
229
230 AccessFlags flags = m.access_flags;
231
232 Descriptor d;
233 Type.MethodType methodType;
234 List<? extends Type> methodExceptions;
235
236 Signature_attribute sigAttr = getSignature(m.attributes);
237 if (sigAttr == null) {
238 d = m.descriptor;
239 methodType = null;
240 methodExceptions = null;
241 } else {
242 Signature methodSig = sigAttr.getParsedSignature();
243 d = methodSig;
244 try {
245 methodType = (Type.MethodType) methodSig.getType(constant_pool);
246 methodExceptions = methodType.throwsTypes;
247 if (methodExceptions != null && methodExceptions.size() == 0)
248 methodExceptions = null;
249 } catch (ConstantPoolException e) {
250 // report error?
251 // fall back on standard descriptor
252 methodType = null;
253 methodExceptions = null;
254 }
255 }
256
257 writeModifiers(flags.getMethodModifiers());
258 if (methodType != null) {
259 writeListIfNotEmpty("<", methodType.typeArgTypes, "> ");
260 }
261 if (getName(m).equals("<init>")) {
262 print(getJavaName(classFile));
263 print(getParameterTypes(d, flags));
264 } else if (getName(m).equals("<clinit>")) {
265 print("{}");
266 } else {
267 print(getReturnType(d));
268 print(" ");
269 print(getName(m));
270 print(getParameterTypes(d, flags));
271 }
272
273 Attribute e_attr = m.attributes.get(Attribute.Exceptions);
274 if (e_attr != null) { // if there are generic exceptions, there must be erased exceptions
275 if (e_attr instanceof Exceptions_attribute) {
276 Exceptions_attribute exceptions = (Exceptions_attribute) e_attr;
277 if (options.compat) { // Bug XXXXXXX whitespace
278 if (!(options.showLineAndLocalVariableTables
279 || options.showDisassembled
280 || options.verbose
281 || options.showInternalSignatures
282 || options.showAllAttrs)) {
283 print(" ");
284 }
285 print(" ");
286 }
287 print(" throws ");
288 if (methodExceptions != null) { // use generic list if available
289 writeList("", methodExceptions, "");
290 } else {
291 for (int i = 0; i < exceptions.number_of_exceptions; i++) {
292 if (i > 0)
293 print(", ");
294 print(attrWriter.getJavaException(exceptions, i));
295 }
296 }
297 } else {
298 report("Unexpected or invalid value for Exceptions attribute");
299 }
300 }
301
302 print(";");
303 println();
304
305 if (options.showInternalSignatures)
306 println(" Signature: " + getValue(m.descriptor));
307
308 if (options.verbose && !options.compat)
309 writeList(" flags: ", flags.getMethodFlags(), NEWLINE);
310
311 Code_attribute code = null;
312 Attribute c_attr = m.attributes.get(Attribute.Code);
313 if (c_attr != null) {
314 if (c_attr instanceof Code_attribute)
315 code = (Code_attribute) c_attr;
316 else
317 report("Unexpected or invalid value for Code attribute");
318 }
319
320 if (options.showDisassembled && !options.showAllAttrs) {
321 if (code != null) {
322 println(" Code:");
323 codeWriter.writeInstrs(code);
324 codeWriter.writeExceptionTable(code);
325 }
326 println();
327 }
328
329 if (options.showLineAndLocalVariableTables) {
330 if (code != null)
331 attrWriter.write(code, code.attributes.get(Attribute.LineNumberTable), constant_pool);
332 println();
333 if (code != null)
334 attrWriter.write(code, code.attributes.get(Attribute.LocalVariableTable), constant_pool);
335 println();
336 println();
337 }
338
339 if (options.showAllAttrs) {
340 Attribute[] attrs = m.attributes.attrs;
341 for (Attribute attr: attrs)
342 attrWriter.write(m, attr, constant_pool);
343
344 // // the following condition is to mimic old javap
345 // if (!(attrs.length > 0 &&
346 // attrs[attrs.length - 1] instanceof Exceptions_attribute))
347 println();
348 }
349 }
350
351 void writeModifiers(Collection<String> items) {
352 for (Object item: items) {
353 print(item);
354 print(" ");
355 }
356 }
357
358 void writeList(String prefix, Collection<?> items, String suffix) {
359 print(prefix);
360 String sep = "";
361 for (Object item: items) {
362 print(sep);
363 print(item);
364 sep = ", ";
365 }
366 print(suffix);
367 }
368
369 void writeListIfNotEmpty(String prefix, List<?> items, String suffix) {
370 if (items != null && items.size() > 0)
371 writeList(prefix, items, suffix);
372 }
373
374 Signature_attribute getSignature(Attributes attributes) {
375 if (options.compat) // javap does not recognize recent attributes
376 return null;
377 return (Signature_attribute) attributes.get(Attribute.Signature);
378 }
379
380 String adjustVarargs(AccessFlags flags, String params) {
381 if (flags.is(ACC_VARARGS) && !options.compat) {
382 int i = params.lastIndexOf("[]");
383 if (i > 0)
384 return params.substring(0, i) + "..." + params.substring(i+2);
385 }
386
387 return params;
388 }
389
390 String getJavaName(ClassFile cf) {
391 try {
392 return getJavaName(cf.getName());
393 } catch (ConstantPoolException e) {
394 return report(e);
395 }
396 }
397
398 String getJavaSuperclassName(ClassFile cf) {
399 try {
400 return getJavaName(cf.getSuperclassName());
401 } catch (ConstantPoolException e) {
402 return report(e);
403 }
404 }
405
406 String getJavaInterfaceName(ClassFile cf, int index) {
407 try {
408 return getJavaName(cf.getInterfaceName(index));
409 } catch (ConstantPoolException e) {
410 return report(e);
411 }
412 }
413
414 String getFieldType(Descriptor d) {
415 try {
416 return d.getFieldType(constant_pool);
417 } catch (ConstantPoolException e) {
418 return report(e);
419 } catch (DescriptorException e) {
420 return report(e);
421 }
422 }
423
424 String getReturnType(Descriptor d) {
425 try {
426 return d.getReturnType(constant_pool);
427 } catch (ConstantPoolException e) {
428 return report(e);
429 } catch (DescriptorException e) {
430 return report(e);
431 }
432 }
433
434 String getParameterTypes(Descriptor d, AccessFlags flags) {
435 try {
436 return adjustVarargs(flags, d.getParameterTypes(constant_pool));
437 } catch (ConstantPoolException e) {
438 return report(e);
439 } catch (DescriptorException e) {
440 return report(e);
441 }
442 }
443
444 String getValue(Descriptor d) {
445 try {
446 return d.getValue(constant_pool);
447 } catch (ConstantPoolException e) {
448 return report(e);
449 }
450 }
451
452 String getFieldName(Field f) {
453 try {
454 return f.getName(constant_pool);
455 } catch (ConstantPoolException e) {
456 return report(e);
457 }
458 }
459
460 String getName(Method m) {
461 try {
462 return m.getName(constant_pool);
463 } catch (ConstantPoolException e) {
464 return report(e);
465 }
466 }
467
468 static String getJavaName(String name) {
469 return name.replace('/', '.');
470 }
471
472 String getSourceFile(SourceFile_attribute attr) {
473 try {
474 return attr.getSourceFile(constant_pool);
475 } catch (ConstantPoolException e) {
476 return report(e);
477 }
478 }
479
480 private Options options;
481 private AttributeWriter attrWriter;
482 private CodeWriter codeWriter;
483 private ConstantWriter constantWriter;
484 private ClassFile classFile;
485 private ConstantPool constant_pool;
486 private Method method;
487 private static final String NEWLINE = System.getProperty("line.separator", "\n");
488 }

mercurial