Path: blob/master/src/jdk.jdeps/share/classes/com/sun/tools/javap/ClassWriter.java
58461 views
/*1* Copyright (c) 2007, 2019, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package com.sun.tools.javap;2627import java.net.URI;28import java.text.DateFormat;29import java.util.Collection;30import java.util.Date;31import java.util.List;32import java.util.Set;3334import com.sun.tools.classfile.AccessFlags;35import com.sun.tools.classfile.Attribute;36import com.sun.tools.classfile.Attributes;37import com.sun.tools.classfile.ClassFile;38import com.sun.tools.classfile.Code_attribute;39import com.sun.tools.classfile.ConstantPool;40import com.sun.tools.classfile.ConstantPoolException;41import com.sun.tools.classfile.ConstantValue_attribute;42import com.sun.tools.classfile.Descriptor;43import com.sun.tools.classfile.Descriptor.InvalidDescriptor;44import com.sun.tools.classfile.Exceptions_attribute;45import com.sun.tools.classfile.Field;46import com.sun.tools.classfile.Method;47import com.sun.tools.classfile.Module_attribute;48import com.sun.tools.classfile.Signature;49import com.sun.tools.classfile.Signature_attribute;50import com.sun.tools.classfile.SourceFile_attribute;51import com.sun.tools.classfile.Type;52import com.sun.tools.classfile.Type.ArrayType;53import com.sun.tools.classfile.Type.ClassSigType;54import com.sun.tools.classfile.Type.ClassType;55import com.sun.tools.classfile.Type.MethodType;56import com.sun.tools.classfile.Type.SimpleType;57import com.sun.tools.classfile.Type.TypeParamType;58import com.sun.tools.classfile.Type.WildcardType;5960import static com.sun.tools.classfile.AccessFlags.*;61import static com.sun.tools.classfile.ConstantPool.CONSTANT_Module;62import static com.sun.tools.classfile.ConstantPool.CONSTANT_Package;6364/*65* The main javap class to write the contents of a class file as text.66*67* <p><b>This is NOT part of any supported API.68* If you write code that depends on this, you do so at your own risk.69* This code and its internal interfaces are subject to change or70* deletion without notice.</b>71*/72public class ClassWriter extends BasicWriter {73static ClassWriter instance(Context context) {74ClassWriter instance = context.get(ClassWriter.class);75if (instance == null)76instance = new ClassWriter(context);77return instance;78}7980protected ClassWriter(Context context) {81super(context);82context.put(ClassWriter.class, this);83options = Options.instance(context);84attrWriter = AttributeWriter.instance(context);85codeWriter = CodeWriter.instance(context);86constantWriter = ConstantWriter.instance(context);87}8889void setDigest(String name, byte[] digest) {90this.digestName = name;91this.digest = digest;92}9394void setFile(URI uri) {95this.uri = uri;96}9798void setFileSize(int size) {99this.size = size;100}101102void setLastModified(long lastModified) {103this.lastModified = lastModified;104}105106protected ClassFile getClassFile() {107return classFile;108}109110protected void setClassFile(ClassFile cf) {111classFile = cf;112constant_pool = classFile.constant_pool;113}114115protected Method getMethod() {116return method;117}118119protected void setMethod(Method m) {120method = m;121}122123public void write(ClassFile cf) {124setClassFile(cf);125126if (options.sysInfo || options.verbose) {127if (uri != null) {128if (uri.getScheme().equals("file"))129println("Classfile " + uri.getPath());130else131println("Classfile " + uri);132}133indent(+1);134if (lastModified != -1) {135Date lm = new Date(lastModified);136DateFormat df = DateFormat.getDateInstance();137if (size > 0) {138println("Last modified " + df.format(lm) + "; size " + size + " bytes");139} else {140println("Last modified " + df.format(lm));141}142} else if (size > 0) {143println("Size " + size + " bytes");144}145if (digestName != null && digest != null) {146StringBuilder sb = new StringBuilder();147for (byte b: digest)148sb.append(String.format("%02x", b));149println(digestName + " checksum " + sb);150}151}152153Attribute sfa = cf.getAttribute(Attribute.SourceFile);154if (sfa instanceof SourceFile_attribute) {155println("Compiled from \"" + getSourceFile((SourceFile_attribute) sfa) + "\"");156}157158if (options.sysInfo || options.verbose) {159indent(-1);160}161162AccessFlags flags = cf.access_flags;163writeModifiers(flags.getClassModifiers());164165if (classFile.access_flags.is(AccessFlags.ACC_MODULE)) {166Attribute attr = classFile.attributes.get(Attribute.Module);167if (attr instanceof Module_attribute) {168Module_attribute modAttr = (Module_attribute) attr;169String name;170try {171// FIXME: compatibility code172if (constant_pool.get(modAttr.module_name).getTag() == CONSTANT_Module) {173name = getJavaName(constant_pool.getModuleInfo(modAttr.module_name).getName());174} else {175name = getJavaName(constant_pool.getUTF8Value(modAttr.module_name));176}177} catch (ConstantPoolException e) {178name = report(e);179}180if ((modAttr.module_flags & Module_attribute.ACC_OPEN) != 0) {181print("open ");182}183print("module ");184print(name);185if (modAttr.module_version_index != 0) {186print("@");187print(getUTF8Value(modAttr.module_version_index));188}189} else {190// fallback for malformed class files191print("class ");192print(getJavaName(classFile));193}194} else {195if (classFile.isClass())196print("class ");197else if (classFile.isInterface())198print("interface ");199200print(getJavaName(classFile));201}202203Signature_attribute sigAttr = getSignature(cf.attributes);204if (sigAttr == null) {205// use info from class file header206if (classFile.isClass() && classFile.super_class != 0 ) {207String sn = getJavaSuperclassName(cf);208if (!sn.equals("java.lang.Object")) {209print(" extends ");210print(sn);211}212}213for (int i = 0; i < classFile.interfaces.length; i++) {214print(i == 0 ? (classFile.isClass() ? " implements " : " extends ") : ",");215print(getJavaInterfaceName(classFile, i));216}217} else {218try {219Type t = sigAttr.getParsedSignature().getType(constant_pool);220JavaTypePrinter p = new JavaTypePrinter(classFile.isInterface());221// The signature parser cannot disambiguate between a222// FieldType and a ClassSignatureType that only contains a superclass type.223if (t instanceof Type.ClassSigType) {224print(p.print(t));225} else if (options.verbose || !t.isObject()) {226print(" extends ");227print(p.print(t));228}229} catch (ConstantPoolException e) {230print(report(e));231} catch (IllegalStateException e) {232report("Invalid value for Signature attribute: " + e.getMessage());233}234}235236if (options.verbose) {237println();238indent(+1);239println("minor version: " + cf.minor_version);240println("major version: " + cf.major_version);241writeList(String.format("flags: (0x%04x) ", flags.flags), flags.getClassFlags(), "\n");242print("this_class: #" + cf.this_class);243if (cf.this_class != 0) {244tab();245print("// " + constantWriter.stringValue(cf.this_class));246}247println();248print("super_class: #" + cf.super_class);249if (cf.super_class != 0) {250tab();251print("// " + constantWriter.stringValue(cf.super_class));252}253println();254print("interfaces: " + cf.interfaces.length);255print(", fields: " + cf.fields.length);256print(", methods: " + cf.methods.length);257println(", attributes: " + cf.attributes.attrs.length);258indent(-1);259constantWriter.writeConstantPool();260} else {261print(" ");262}263264println("{");265indent(+1);266if (flags.is(AccessFlags.ACC_MODULE) && !options.verbose) {267writeDirectives();268}269writeFields();270writeMethods();271indent(-1);272println("}");273274if (options.verbose) {275attrWriter.write(cf, cf.attributes, constant_pool);276}277}278// where279class JavaTypePrinter implements Type.Visitor<StringBuilder,StringBuilder> {280boolean isInterface;281282JavaTypePrinter(boolean isInterface) {283this.isInterface = isInterface;284}285286String print(Type t) {287return t.accept(this, new StringBuilder()).toString();288}289290String printTypeArgs(List<? extends TypeParamType> typeParamTypes) {291StringBuilder builder = new StringBuilder();292appendIfNotEmpty(builder, "<", typeParamTypes, "> ");293return builder.toString();294}295296@Override297public StringBuilder visitSimpleType(SimpleType type, StringBuilder sb) {298sb.append(getJavaName(type.name));299return sb;300}301302@Override303public StringBuilder visitArrayType(ArrayType type, StringBuilder sb) {304append(sb, type.elemType);305sb.append("[]");306return sb;307}308309@Override310public StringBuilder visitMethodType(MethodType type, StringBuilder sb) {311appendIfNotEmpty(sb, "<", type.typeParamTypes, "> ");312append(sb, type.returnType);313append(sb, " (", type.paramTypes, ")");314appendIfNotEmpty(sb, " throws ", type.throwsTypes, "");315return sb;316}317318@Override319public StringBuilder visitClassSigType(ClassSigType type, StringBuilder sb) {320appendIfNotEmpty(sb, "<", type.typeParamTypes, ">");321if (isInterface) {322appendIfNotEmpty(sb, " extends ", type.superinterfaceTypes, "");323} else {324if (type.superclassType != null325&& (options.verbose || !type.superclassType.isObject())) {326sb.append(" extends ");327append(sb, type.superclassType);328}329appendIfNotEmpty(sb, " implements ", type.superinterfaceTypes, "");330}331return sb;332}333334@Override335public StringBuilder visitClassType(ClassType type, StringBuilder sb) {336if (type.outerType != null) {337append(sb, type.outerType);338sb.append(".");339}340sb.append(getJavaName(type.name));341appendIfNotEmpty(sb, "<", type.typeArgs, ">");342return sb;343}344345@Override346public StringBuilder visitTypeParamType(TypeParamType type, StringBuilder sb) {347sb.append(type.name);348String sep = " extends ";349if (type.classBound != null350&& (options.verbose || !type.classBound.isObject())) {351sb.append(sep);352append(sb, type.classBound);353sep = " & ";354}355if (type.interfaceBounds != null) {356for (Type bound: type.interfaceBounds) {357sb.append(sep);358append(sb, bound);359sep = " & ";360}361}362return sb;363}364365@Override366public StringBuilder visitWildcardType(WildcardType type, StringBuilder sb) {367switch (type.kind) {368case UNBOUNDED:369sb.append("?");370break;371case EXTENDS:372sb.append("? extends ");373append(sb, type.boundType);374break;375case SUPER:376sb.append("? super ");377append(sb, type.boundType);378break;379default:380throw new AssertionError();381}382return sb;383}384385private void append(StringBuilder sb, Type t) {386t.accept(this, sb);387}388389private void append(StringBuilder sb, String prefix, List<? extends Type> list, String suffix) {390sb.append(prefix);391String sep = "";392for (Type t: list) {393sb.append(sep);394append(sb, t);395sep = ", ";396}397sb.append(suffix);398}399400private void appendIfNotEmpty(StringBuilder sb, String prefix, List<? extends Type> list, String suffix) {401if (!isEmpty(list))402append(sb, prefix, list, suffix);403}404405private boolean isEmpty(List<? extends Type> list) {406return (list == null || list.isEmpty());407}408}409410protected void writeFields() {411for (Field f: classFile.fields) {412writeField(f);413}414}415416protected void writeField(Field f) {417if (!options.checkAccess(f.access_flags))418return;419420AccessFlags flags = f.access_flags;421writeModifiers(flags.getFieldModifiers());422Signature_attribute sigAttr = getSignature(f.attributes);423if (sigAttr == null)424print(getJavaFieldType(f.descriptor));425else {426try {427Type t = sigAttr.getParsedSignature().getType(constant_pool);428print(getJavaName(t.toString()));429} catch (ConstantPoolException e) {430// report error?431// fall back on non-generic descriptor432print(getJavaFieldType(f.descriptor));433}434}435print(" ");436print(getFieldName(f));437if (options.showConstants) {438Attribute a = f.attributes.get(Attribute.ConstantValue);439if (a instanceof ConstantValue_attribute) {440print(" = ");441ConstantValue_attribute cv = (ConstantValue_attribute) a;442print(getConstantValue(f.descriptor, cv.constantvalue_index));443}444}445print(";");446println();447448indent(+1);449450boolean showBlank = false;451452if (options.showDescriptors)453println("descriptor: " + getValue(f.descriptor));454455if (options.verbose)456writeList(String.format("flags: (0x%04x) ", flags.flags), flags.getFieldFlags(), "\n");457458if (options.showAllAttrs) {459for (Attribute attr: f.attributes)460attrWriter.write(f, attr, constant_pool);461showBlank = true;462}463464indent(-1);465466if (showBlank || options.showDisassembled || options.showLineAndLocalVariableTables)467println();468}469470protected void writeMethods() {471for (Method m: classFile.methods)472writeMethod(m);473setPendingNewline(false);474}475476private static final int DEFAULT_ALLOWED_MAJOR_VERSION = 52;477private static final int DEFAULT_ALLOWED_MINOR_VERSION = 0;478479protected void writeMethod(Method m) {480if (!options.checkAccess(m.access_flags))481return;482483method = m;484485AccessFlags flags = m.access_flags;486487Descriptor d;488Type.MethodType methodType;489List<? extends Type> methodExceptions;490491Signature_attribute sigAttr = getSignature(m.attributes);492if (sigAttr == null) {493d = m.descriptor;494methodType = null;495methodExceptions = null;496} else {497Signature methodSig = sigAttr.getParsedSignature();498d = methodSig;499try {500methodType = (Type.MethodType) methodSig.getType(constant_pool);501methodExceptions = methodType.throwsTypes;502if (methodExceptions != null && methodExceptions.isEmpty())503methodExceptions = null;504} catch (ConstantPoolException | IllegalStateException e) {505// report error?506// fall back on standard descriptor507methodType = null;508methodExceptions = null;509}510}511512Set<String> modifiers = flags.getMethodModifiers();513514String name = getName(m);515if (classFile.isInterface() &&516(!flags.is(AccessFlags.ACC_ABSTRACT)) && !name.equals("<clinit>")) {517if (classFile.major_version > DEFAULT_ALLOWED_MAJOR_VERSION ||518(classFile.major_version == DEFAULT_ALLOWED_MAJOR_VERSION && classFile.minor_version >= DEFAULT_ALLOWED_MINOR_VERSION)) {519if (!flags.is(AccessFlags.ACC_STATIC | AccessFlags.ACC_PRIVATE)) {520modifiers.add("default");521}522}523}524525writeModifiers(modifiers);526if (methodType != null) {527print(new JavaTypePrinter(false).printTypeArgs(methodType.typeParamTypes));528}529switch (name) {530case "<init>":531print(getJavaName(classFile));532print(getJavaParameterTypes(d, flags));533break;534case "<clinit>":535print("{}");536break;537default:538print(getJavaReturnType(d));539print(" ");540print(name);541print(getJavaParameterTypes(d, flags));542break;543}544545Attribute e_attr = m.attributes.get(Attribute.Exceptions);546if (e_attr != null) { // if there are generic exceptions, there must be erased exceptions547if (e_attr instanceof Exceptions_attribute) {548Exceptions_attribute exceptions = (Exceptions_attribute) e_attr;549print(" throws ");550if (methodExceptions != null) { // use generic list if available551writeList("", methodExceptions, "");552} else {553for (int i = 0; i < exceptions.number_of_exceptions; i++) {554if (i > 0)555print(", ");556print(getJavaException(exceptions, i));557}558}559} else {560report("Unexpected or invalid value for Exceptions attribute");561}562}563564println(";");565566indent(+1);567568if (options.showDescriptors) {569println("descriptor: " + getValue(m.descriptor));570}571572if (options.verbose) {573writeList(String.format("flags: (0x%04x) ", flags.flags), flags.getMethodFlags(), "\n");574}575576Code_attribute code = null;577Attribute c_attr = m.attributes.get(Attribute.Code);578if (c_attr != null) {579if (c_attr instanceof Code_attribute)580code = (Code_attribute) c_attr;581else582report("Unexpected or invalid value for Code attribute");583}584585if (options.showAllAttrs) {586Attribute[] attrs = m.attributes.attrs;587for (Attribute attr: attrs)588attrWriter.write(m, attr, constant_pool);589} else if (code != null) {590if (options.showDisassembled) {591println("Code:");592codeWriter.writeInstrs(code);593codeWriter.writeExceptionTable(code);594}595596if (options.showLineAndLocalVariableTables) {597attrWriter.write(code, code.attributes.get(Attribute.LineNumberTable), constant_pool);598attrWriter.write(code, code.attributes.get(Attribute.LocalVariableTable), constant_pool);599}600}601602indent(-1);603604// set pendingNewline to write a newline before the next method (if any)605// if a separator is desired606setPendingNewline(607options.showDisassembled ||608options.showAllAttrs ||609options.showDescriptors ||610options.showLineAndLocalVariableTables ||611options.verbose);612}613614void writeModifiers(Collection<String> items) {615for (Object item: items) {616print(item);617print(" ");618}619}620621void writeDirectives() {622Attribute attr = classFile.attributes.get(Attribute.Module);623if (!(attr instanceof Module_attribute))624return;625626Module_attribute m = (Module_attribute) attr;627for (Module_attribute.RequiresEntry entry: m.requires) {628print("requires");629if ((entry.requires_flags & Module_attribute.ACC_STATIC_PHASE) != 0)630print(" static");631if ((entry.requires_flags & Module_attribute.ACC_TRANSITIVE) != 0)632print(" transitive");633print(" ");634String mname;635try {636mname = getModuleName(entry.requires_index);637} catch (ConstantPoolException e) {638mname = report(e);639}640print(mname);641println(";");642}643644for (Module_attribute.ExportsEntry entry: m.exports) {645print("exports");646print(" ");647String pname;648try {649pname = getPackageName(entry.exports_index).replace('/', '.');650} catch (ConstantPoolException e) {651pname = report(e);652}653print(pname);654boolean first = true;655for (int i: entry.exports_to_index) {656String mname;657try {658mname = getModuleName(i);659} catch (ConstantPoolException e) {660mname = report(e);661}662if (first) {663println(" to");664indent(+1);665first = false;666} else {667println(",");668}669print(mname);670}671println(";");672if (!first)673indent(-1);674}675676for (Module_attribute.OpensEntry entry: m.opens) {677print("opens");678print(" ");679String pname;680try {681pname = getPackageName(entry.opens_index).replace('/', '.');682} catch (ConstantPoolException e) {683pname = report(e);684}685print(pname);686boolean first = true;687for (int i: entry.opens_to_index) {688String mname;689try {690mname = getModuleName(i);691} catch (ConstantPoolException e) {692mname = report(e);693}694if (first) {695println(" to");696indent(+1);697first = false;698} else {699println(",");700}701print(mname);702}703println(";");704if (!first)705indent(-1);706}707708for (int entry: m.uses_index) {709print("uses ");710print(getClassName(entry).replace('/', '.'));711println(";");712}713714for (Module_attribute.ProvidesEntry entry: m.provides) {715print("provides ");716print(getClassName(entry.provides_index).replace('/', '.'));717boolean first = true;718for (int i: entry.with_index) {719if (first) {720println(" with");721indent(+1);722first = false;723} else {724println(",");725}726print(getClassName(i).replace('/', '.'));727}728println(";");729if (!first)730indent(-1);731}732}733734String getModuleName(int index) throws ConstantPoolException {735if (constant_pool.get(index).getTag() == CONSTANT_Module) {736return constant_pool.getModuleInfo(index).getName();737} else {738return constant_pool.getUTF8Value(index);739}740}741742String getPackageName(int index) throws ConstantPoolException {743if (constant_pool.get(index).getTag() == CONSTANT_Package) {744return constant_pool.getPackageInfo(index).getName();745} else {746return constant_pool.getUTF8Value(index);747}748}749750String getUTF8Value(int index) {751try {752return classFile.constant_pool.getUTF8Value(index);753} catch (ConstantPoolException e) {754return report(e);755}756}757758String getClassName(int index) {759try {760return classFile.constant_pool.getClassInfo(index).getName();761} catch (ConstantPoolException e) {762return report(e);763}764}765766void writeList(String prefix, Collection<?> items, String suffix) {767print(prefix);768String sep = "";769for (Object item: items) {770print(sep);771print(item);772sep = ", ";773}774print(suffix);775}776777void writeListIfNotEmpty(String prefix, List<?> items, String suffix) {778if (items != null && items.size() > 0)779writeList(prefix, items, suffix);780}781782Signature_attribute getSignature(Attributes attributes) {783return (Signature_attribute) attributes.get(Attribute.Signature);784}785786String adjustVarargs(AccessFlags flags, String params) {787if (flags.is(ACC_VARARGS)) {788int i = params.lastIndexOf("[]");789if (i > 0)790return params.substring(0, i) + "..." + params.substring(i+2);791}792793return params;794}795796String getJavaName(ClassFile cf) {797try {798return getJavaName(cf.getName());799} catch (ConstantPoolException e) {800return report(e);801}802}803804String getJavaSuperclassName(ClassFile cf) {805try {806return getJavaName(cf.getSuperclassName());807} catch (ConstantPoolException e) {808return report(e);809}810}811812String getJavaInterfaceName(ClassFile cf, int index) {813try {814return getJavaName(cf.getInterfaceName(index));815} catch (ConstantPoolException e) {816return report(e);817}818}819820String getJavaFieldType(Descriptor d) {821try {822return getJavaName(d.getFieldType(constant_pool));823} catch (ConstantPoolException e) {824return report(e);825} catch (InvalidDescriptor e) {826return report(e);827}828}829830String getJavaReturnType(Descriptor d) {831try {832return getJavaName(d.getReturnType(constant_pool));833} catch (ConstantPoolException e) {834return report(e);835} catch (InvalidDescriptor e) {836return report(e);837}838}839840String getJavaParameterTypes(Descriptor d, AccessFlags flags) {841try {842return getJavaName(adjustVarargs(flags, d.getParameterTypes(constant_pool)));843} catch (ConstantPoolException e) {844return report(e);845} catch (InvalidDescriptor e) {846return report(e);847}848}849850String getJavaException(Exceptions_attribute attr, int index) {851try {852return getJavaName(attr.getException(index, constant_pool));853} catch (ConstantPoolException e) {854return report(e);855}856}857858String getValue(Descriptor d) {859try {860return d.getValue(constant_pool);861} catch (ConstantPoolException e) {862return report(e);863}864}865866String getFieldName(Field f) {867try {868return f.getName(constant_pool);869} catch (ConstantPoolException e) {870return report(e);871}872}873874String getName(Method m) {875try {876return m.getName(constant_pool);877} catch (ConstantPoolException e) {878return report(e);879}880}881882static String getJavaName(String name) {883return name.replace('/', '.');884}885886String getSourceFile(SourceFile_attribute attr) {887try {888return attr.getSourceFile(constant_pool);889} catch (ConstantPoolException e) {890return report(e);891}892}893894/**895* Get the value of an entry in the constant pool as a Java constant.896* Characters and booleans are represented by CONSTANT_Intgere entries.897* Character and string values are processed to escape characters outside898* the basic printable ASCII set.899* @param d the descriptor, giving the expected type of the constant900* @param index the index of the value in the constant pool901* @return a printable string containing the value of the constant.902*/903String getConstantValue(Descriptor d, int index) {904try {905ConstantPool.CPInfo cpInfo = constant_pool.get(index);906907switch (cpInfo.getTag()) {908case ConstantPool.CONSTANT_Integer: {909ConstantPool.CONSTANT_Integer_info info =910(ConstantPool.CONSTANT_Integer_info) cpInfo;911String t = d.getValue(constant_pool);912switch (t) {913case "C":914// character915return getConstantCharValue((char) info.value);916case "Z":917// boolean918return String.valueOf(info.value == 1);919default:920// other: assume integer921return String.valueOf(info.value);922}923}924925case ConstantPool.CONSTANT_String: {926ConstantPool.CONSTANT_String_info info =927(ConstantPool.CONSTANT_String_info) cpInfo;928return getConstantStringValue(info.getString());929}930931default:932return constantWriter.stringValue(cpInfo);933}934} catch (ConstantPoolException e) {935return "#" + index;936}937}938939private String getConstantCharValue(char c) {940StringBuilder sb = new StringBuilder();941sb.append('\'');942sb.append(esc(c, '\''));943sb.append('\'');944return sb.toString();945}946947private String getConstantStringValue(String s) {948StringBuilder sb = new StringBuilder();949sb.append("\"");950for (int i = 0; i < s.length(); i++) {951sb.append(esc(s.charAt(i), '"'));952}953sb.append("\"");954return sb.toString();955}956957private String esc(char c, char quote) {958if (32 <= c && c <= 126 && c != quote && c != '\\')959return String.valueOf(c);960else switch (c) {961case '\b': return "\\b";962case '\n': return "\\n";963case '\t': return "\\t";964case '\f': return "\\f";965case '\r': return "\\r";966case '\\': return "\\\\";967case '\'': return "\\'";968case '\"': return "\\\"";969default: return String.format("\\u%04x", (int) c);970}971}972973private final Options options;974private final AttributeWriter attrWriter;975private final CodeWriter codeWriter;976private final ConstantWriter constantWriter;977private ClassFile classFile;978private URI uri;979private long lastModified;980private String digestName;981private byte[] digest;982private int size;983private ConstantPool constant_pool;984private Method method;985}986987988