/* * Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Sun designates this * particular file as subject to the "Classpath" exception as provided * by Sun in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ package com.sun.tools.javap; import java.net.URI; import java.util.Collection; import java.util.List; import com.sun.tools.classfile.AccessFlags; import com.sun.tools.classfile.Attribute; import com.sun.tools.classfile.Attributes; import com.sun.tools.classfile.ClassFile; import com.sun.tools.classfile.Code_attribute; import com.sun.tools.classfile.ConstantPool; import com.sun.tools.classfile.ConstantPoolException; import com.sun.tools.classfile.ConstantValue_attribute; import com.sun.tools.classfile.Descriptor; import com.sun.tools.classfile.DescriptorException; import com.sun.tools.classfile.Exceptions_attribute; import com.sun.tools.classfile.Field; import com.sun.tools.classfile.Method; import com.sun.tools.classfile.Signature; import com.sun.tools.classfile.Signature_attribute; import com.sun.tools.classfile.SourceFile_attribute; import com.sun.tools.classfile.Type; import java.text.DateFormat; import java.util.Date; import static com.sun.tools.classfile.AccessFlags.*; /* * The main javap class to write the contents of a class file as text. * *
This is NOT part of any API supported by Sun Microsystems. If
* you write code that depends on this, you do so at your own risk.
* This code and its internal interfaces are subject to change or
* deletion without notice.
*/
public class ClassWriter extends BasicWriter {
static ClassWriter instance(Context context) {
ClassWriter instance = context.get(ClassWriter.class);
if (instance == null)
instance = new ClassWriter(context);
return instance;
}
protected ClassWriter(Context context) {
super(context);
context.put(ClassWriter.class, this);
options = Options.instance(context);
attrWriter = AttributeWriter.instance(context);
codeWriter = CodeWriter.instance(context);
constantWriter = ConstantWriter.instance(context);
}
void setDigest(String name, byte[] digest) {
this.digestName = name;
this.digest = digest;
}
void setFile(URI uri) {
this.uri = uri;
}
void setFileSize(int size) {
this.size = size;
}
void setLastModified(long lastModified) {
this.lastModified = lastModified;
}
ClassFile getClassFile() {
return classFile;
}
Method getMethod() {
return method;
}
public void write(ClassFile cf) {
classFile = cf;
constant_pool = classFile.constant_pool;
if ((options.sysInfo || options.verbose) && !options.compat) {
if (uri != null) {
if (uri.getScheme().equals("file"))
println("Classfile " + uri.getPath());
else
println("Classfile " + uri);
}
if (lastModified != -1) {
Date lm = new Date(lastModified);
DateFormat df = DateFormat.getDateInstance();
if (size > 0) {
println("Last modified " + df.format(lm) + "; size " + size + " bytes");
} else {
println("Last modified " + df.format(lm));
}
} else if (size > 0) {
println("Size " + size + " bytes");
}
if (digestName != null && digest != null) {
StringBuilder sb = new StringBuilder();
for (byte b: digest)
sb.append(String.format("%02x", b));
println(digestName + " checksum " + sb);
}
}
Attribute sfa = cf.getAttribute(Attribute.SourceFile);
if (sfa instanceof SourceFile_attribute) {
println("Compiled from \"" + getSourceFile((SourceFile_attribute) sfa) + "\"");
}
String name = getJavaName(classFile);
AccessFlags flags = cf.access_flags;
writeModifiers(flags.getClassModifiers());
if (classFile.isClass())
print("class ");
else if (classFile.isInterface())
print("interface ");
print(name);
Signature_attribute sigAttr = getSignature(cf.attributes);
if (sigAttr == null) {
// use info from class file header
if (classFile.isClass() && classFile.super_class != 0 ) {
String sn = getJavaSuperclassName(cf);
print(" extends ");
print(sn);
}
for (int i = 0; i < classFile.interfaces.length; i++) {
print(i == 0 ? (classFile.isClass() ? " implements " : " extends ") : ",");
print(getJavaInterfaceName(classFile, i));
}
} else {
try {
Type t = sigAttr.getParsedSignature().getType(constant_pool);
// The signature parser cannot disambiguate between a
// FieldType and a ClassSignatureType that only contains a superclass type.
if (t instanceof Type.ClassSigType)
print(t);
else {
print(" extends ");
print(t);
}
} catch (ConstantPoolException e) {
print(report(e));
}
}
if (options.verbose) {
println();
attrWriter.write(cf, cf.attributes, constant_pool);
println(" minor version: " + cf.minor_version);
println(" major version: " + cf.major_version);
if (!options.compat)
writeList(" flags: ", flags.getClassFlags(), NEWLINE);
constantWriter.writeConstantPool();
println();
} else {
if (!options.compat)
print(" ");
}
println("{");
writeFields();
writeMethods();
println("}");
println();
}
void writeFields() {
for (Field f: classFile.fields) {
writeField(f);
}
}
void writeField(Field f) {
if (!options.checkAccess(f.access_flags))
return;
if (!(options.showLineAndLocalVariableTables
|| options.showDisassembled
|| options.verbose
|| options.showInternalSignatures
|| options.showAllAttrs)) {
print(" ");
}
AccessFlags flags = f.access_flags;
writeModifiers(flags.getFieldModifiers());
Signature_attribute sigAttr = getSignature(f.attributes);
if (sigAttr == null)
print(getFieldType(f.descriptor));
else {
try {
Type t = sigAttr.getParsedSignature().getType(constant_pool);
print(t);
} catch (ConstantPoolException e) {
// report error?
// fall back on non-generic descriptor
print(getFieldType(f.descriptor));
}
}
print(" ");
print(getFieldName(f));
if (options.showConstants && !options.compat) { // BUG 4111861 print static final field contents
Attribute a = f.attributes.get(Attribute.ConstantValue);
if (a instanceof ConstantValue_attribute) {
print(" = ");
ConstantValue_attribute cv = (ConstantValue_attribute) a;
print(getConstantValue(f.descriptor, cv.constantvalue_index));
}
}
print(";");
println();
if (options.showInternalSignatures)
println(" Signature: " + getValue(f.descriptor));
if (options.verbose && !options.compat)
writeList(" flags: ", flags.getFieldFlags(), NEWLINE);
if (options.showAllAttrs) {
for (Attribute attr: f.attributes)
attrWriter.write(f, attr, constant_pool);
println();
}
if (options.showDisassembled || options.showLineAndLocalVariableTables)
println();
}
void writeMethods() {
for (Method m: classFile.methods)
writeMethod(m);
}
void writeMethod(Method m) {
if (!options.checkAccess(m.access_flags))
return;
method = m;
if (!(options.showLineAndLocalVariableTables
|| options.showDisassembled
|| options.verbose
|| options.showInternalSignatures
|| options.showAllAttrs)) {
print(" ");
}
AccessFlags flags = m.access_flags;
Descriptor d;
Type.MethodType methodType;
List extends Type> methodExceptions;
Signature_attribute sigAttr = getSignature(m.attributes);
if (sigAttr == null) {
d = m.descriptor;
methodType = null;
methodExceptions = null;
} else {
Signature methodSig = sigAttr.getParsedSignature();
d = methodSig;
try {
methodType = (Type.MethodType) methodSig.getType(constant_pool);
methodExceptions = methodType.throwsTypes;
if (methodExceptions != null && methodExceptions.size() == 0)
methodExceptions = null;
} catch (ConstantPoolException e) {
// report error?
// fall back on standard descriptor
methodType = null;
methodExceptions = null;
}
}
writeModifiers(flags.getMethodModifiers());
if (methodType != null) {
writeListIfNotEmpty("<", methodType.typeArgTypes, "> ");
}
if (getName(m).equals("