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

Fri, 04 Oct 2013 16:08:18 -0700

author
ksrini
date
Fri, 04 Oct 2013 16:08:18 -0700
changeset 2089
bb87db832b31
parent 1578
040f02711b73
child 2267
3b9176029091
permissions
-rw-r--r--

8003537: javap use internal class name when printing bound of type variable
Reviewed-by: jjg

     1 /*
     2  * Copyright (c) 2007, 2013, Oracle and/or its affiliates. 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.  Oracle designates this
     8  * particular file as subject to the "Classpath" exception as provided
     9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
    22  * or visit www.oracle.com if you need additional information or have any
    23  * questions.
    24  */
    26 package com.sun.tools.javap;
    28 import java.net.URI;
    29 import java.text.DateFormat;
    30 import java.util.Collection;
    31 import java.util.Date;
    32 import java.util.List;
    34 import com.sun.tools.classfile.AccessFlags;
    35 import com.sun.tools.classfile.Attribute;
    36 import com.sun.tools.classfile.Attributes;
    37 import com.sun.tools.classfile.ClassFile;
    38 import com.sun.tools.classfile.Code_attribute;
    39 import com.sun.tools.classfile.ConstantPool;
    40 import com.sun.tools.classfile.ConstantPoolException;
    41 import com.sun.tools.classfile.ConstantValue_attribute;
    42 import com.sun.tools.classfile.Descriptor;
    43 import com.sun.tools.classfile.DescriptorException;
    44 import com.sun.tools.classfile.Exceptions_attribute;
    45 import com.sun.tools.classfile.Field;
    46 import com.sun.tools.classfile.Method;
    47 import com.sun.tools.classfile.Signature;
    48 import com.sun.tools.classfile.Signature_attribute;
    49 import com.sun.tools.classfile.SourceFile_attribute;
    50 import com.sun.tools.classfile.Type;
    51 import com.sun.tools.classfile.Type.ArrayType;
    52 import com.sun.tools.classfile.Type.ClassSigType;
    53 import com.sun.tools.classfile.Type.ClassType;
    54 import com.sun.tools.classfile.Type.MethodType;
    55 import com.sun.tools.classfile.Type.SimpleType;
    56 import com.sun.tools.classfile.Type.TypeParamType;
    57 import com.sun.tools.classfile.Type.WildcardType;
    59 import static com.sun.tools.classfile.AccessFlags.*;
    61 /*
    62  *  The main javap class to write the contents of a class file as text.
    63  *
    64  *  <p><b>This is NOT part of any supported API.
    65  *  If you write code that depends on this, you do so at your own risk.
    66  *  This code and its internal interfaces are subject to change or
    67  *  deletion without notice.</b>
    68  */
    69 public class ClassWriter extends BasicWriter {
    70     static ClassWriter instance(Context context) {
    71         ClassWriter instance = context.get(ClassWriter.class);
    72         if (instance == null)
    73             instance = new ClassWriter(context);
    74         return instance;
    75     }
    77     protected ClassWriter(Context context) {
    78         super(context);
    79         context.put(ClassWriter.class, this);
    80         options = Options.instance(context);
    81         attrWriter = AttributeWriter.instance(context);
    82         codeWriter = CodeWriter.instance(context);
    83         constantWriter = ConstantWriter.instance(context);
    84     }
    86     void setDigest(String name, byte[] digest) {
    87         this.digestName = name;
    88         this.digest = digest;
    89     }
    91     void setFile(URI uri) {
    92         this.uri = uri;
    93     }
    95     void setFileSize(int size) {
    96         this.size = size;
    97     }
    99     void setLastModified(long lastModified) {
   100         this.lastModified = lastModified;
   101     }
   103     protected ClassFile getClassFile() {
   104         return classFile;
   105     }
   107     protected void setClassFile(ClassFile cf) {
   108         classFile = cf;
   109         constant_pool = classFile.constant_pool;
   110     }
   112     protected Method getMethod() {
   113         return method;
   114     }
   116     protected void setMethod(Method m) {
   117         method = m;
   118     }
   120     public void write(ClassFile cf) {
   121         setClassFile(cf);
   123         if ((options.sysInfo || options.verbose) && !options.compat) {
   124             if (uri != null) {
   125                 if (uri.getScheme().equals("file"))
   126                     println("Classfile " + uri.getPath());
   127                 else
   128                     println("Classfile " + uri);
   129             }
   130             indent(+1);
   131             if (lastModified != -1) {
   132                 Date lm = new Date(lastModified);
   133                 DateFormat df = DateFormat.getDateInstance();
   134                 if (size > 0) {
   135                     println("Last modified " + df.format(lm) + "; size " + size + " bytes");
   136                 } else {
   137                     println("Last modified " + df.format(lm));
   138                 }
   139             } else if (size > 0) {
   140                 println("Size " + size + " bytes");
   141             }
   142             if (digestName != null && digest != null) {
   143                 StringBuilder sb = new StringBuilder();
   144                 for (byte b: digest)
   145                     sb.append(String.format("%02x", b));
   146                 println(digestName + " checksum " + sb);
   147             }
   148         }
   150         Attribute sfa = cf.getAttribute(Attribute.SourceFile);
   151         if (sfa instanceof SourceFile_attribute) {
   152             println("Compiled from \"" + getSourceFile((SourceFile_attribute) sfa) + "\"");
   153         }
   155         if ((options.sysInfo || options.verbose) && !options.compat) {
   156             indent(-1);
   157         }
   159         String name = getJavaName(classFile);
   160         AccessFlags flags = cf.access_flags;
   162         writeModifiers(flags.getClassModifiers());
   164         if (classFile.isClass())
   165             print("class ");
   166         else if (classFile.isInterface())
   167             print("interface ");
   169         print(name);
   171         Signature_attribute sigAttr = getSignature(cf.attributes);
   172         if (sigAttr == null) {
   173             // use info from class file header
   174             if (classFile.isClass() && classFile.super_class != 0 ) {
   175                 String sn = getJavaSuperclassName(cf);
   176                 if (!sn.equals("java.lang.Object")) {
   177                     print(" extends ");
   178                     print(sn);
   179                 }
   180             }
   181             for (int i = 0; i < classFile.interfaces.length; i++) {
   182                 print(i == 0 ? (classFile.isClass() ? " implements " : " extends ") : ",");
   183                 print(getJavaInterfaceName(classFile, i));
   184             }
   185         } else {
   186             try {
   187                 Type t = sigAttr.getParsedSignature().getType(constant_pool);
   188                 JavaTypePrinter p = new JavaTypePrinter(classFile.isInterface());
   189                 // The signature parser cannot disambiguate between a
   190                 // FieldType and a ClassSignatureType that only contains a superclass type.
   191                 if (t instanceof Type.ClassSigType) {
   192                     print(p.print(t));
   193                 } else if (options.verbose || !t.isObject()) {
   194                     print(" extends ");
   195                     print(p.print(t));
   196                 }
   197             } catch (ConstantPoolException e) {
   198                 print(report(e));
   199             }
   200         }
   202         if (options.verbose) {
   203             println();
   204             indent(+1);
   205             attrWriter.write(cf, cf.attributes, constant_pool);
   206             println("minor version: " + cf.minor_version);
   207             println("major version: " + cf.major_version);
   208             if (!options.compat)
   209               writeList("flags: ", flags.getClassFlags(), "\n");
   210             indent(-1);
   211             constantWriter.writeConstantPool();
   212         } else {
   213             print(" ");
   214         }
   216         println("{");
   217         indent(+1);
   218         writeFields();
   219         writeMethods();
   220         indent(-1);
   221         println("}");
   222     }
   223     // where
   224         class JavaTypePrinter implements Type.Visitor<StringBuilder,StringBuilder> {
   225             boolean isInterface;
   227             JavaTypePrinter(boolean isInterface) {
   228                 this.isInterface = isInterface;
   229             }
   231             String print(Type t) {
   232                 return t.accept(this, new StringBuilder()).toString();
   233             }
   235             String printTypeArgs(List<? extends TypeParamType> typeParamTypes) {
   236                 StringBuilder builder = new StringBuilder();
   237                 appendIfNotEmpty(builder, "<", typeParamTypes, "> ");
   238                 return builder.toString();
   239             }
   241             public StringBuilder visitSimpleType(SimpleType type, StringBuilder sb) {
   242                 sb.append(getJavaName(type.name));
   243                 return sb;
   244             }
   246             public StringBuilder visitArrayType(ArrayType type, StringBuilder sb) {
   247                 append(sb, type.elemType);
   248                 sb.append("[]");
   249                 return sb;
   250             }
   252             public StringBuilder visitMethodType(MethodType type, StringBuilder sb) {
   253                 appendIfNotEmpty(sb, "<", type.typeParamTypes, "> ");
   254                 append(sb, type.returnType);
   255                 append(sb, " (", type.paramTypes, ")");
   256                 appendIfNotEmpty(sb, " throws ", type.throwsTypes, "");
   257                 return sb;
   258             }
   260             public StringBuilder visitClassSigType(ClassSigType type, StringBuilder sb) {
   261                 appendIfNotEmpty(sb, "<", type.typeParamTypes, ">");
   262                 if (isInterface) {
   263                     appendIfNotEmpty(sb, " extends ", type.superinterfaceTypes, "");
   264                 } else {
   265                     if (type.superclassType != null
   266                             && (options.verbose || !type.superclassType.isObject())) {
   267                         sb.append(" extends ");
   268                         append(sb, type.superclassType);
   269                     }
   270                     appendIfNotEmpty(sb, " implements ", type.superinterfaceTypes, "");
   271                 }
   272                 return sb;
   273             }
   275             public StringBuilder visitClassType(ClassType type, StringBuilder sb) {
   276                 if (type.outerType != null) {
   277                     append(sb, type.outerType);
   278                     sb.append(".");
   279                 }
   280                 sb.append(getJavaName(type.name));
   281                 appendIfNotEmpty(sb, "<", type.typeArgs, ">");
   282                 return sb;
   283             }
   285             public StringBuilder visitTypeParamType(TypeParamType type, StringBuilder sb) {
   286                 sb.append(type.name);
   287                 String sep = " extends ";
   288                 if (type.classBound != null
   289                         && (options.verbose || !type.classBound.isObject())) {
   290                     sb.append(sep);
   291                     append(sb, type.classBound);
   292                     sep = " & ";
   293                 }
   294                 if (type.interfaceBounds != null) {
   295                     for (Type bound: type.interfaceBounds) {
   296                         sb.append(sep);
   297                         append(sb, bound);
   298                         sep = " & ";
   299                     }
   300                 }
   301                 return sb;
   302             }
   304             public StringBuilder visitWildcardType(WildcardType type, StringBuilder sb) {
   305                 switch (type.kind) {
   306                     case UNBOUNDED:
   307                         sb.append("?");
   308                         break;
   309                     case EXTENDS:
   310                         sb.append("? extends ");
   311                         append(sb, type.boundType);
   312                         break;
   313                     case SUPER:
   314                         sb.append("? super ");
   315                         append(sb, type.boundType);
   316                         break;
   317                     default:
   318                         throw new AssertionError();
   319                 }
   320                 return sb;
   321             }
   323             private void append(StringBuilder sb, Type t) {
   324                 t.accept(this, sb);
   325             }
   327             private void append(StringBuilder sb, String prefix, List<? extends Type> list, String suffix) {
   328                 sb.append(prefix);
   329                 String sep = "";
   330                 for (Type t: list) {
   331                     sb.append(sep);
   332                     append(sb, t);
   333                     sep = ", ";
   334                 }
   335                 sb.append(suffix);
   336             }
   338             private void appendIfNotEmpty(StringBuilder sb, String prefix, List<? extends Type> list, String suffix) {
   339                 if (!isEmpty(list))
   340                     append(sb, prefix, list, suffix);
   341             }
   343             private boolean isEmpty(List<? extends Type> list) {
   344                 return (list == null || list.isEmpty());
   345             }
   346         }
   348     protected void writeFields() {
   349         for (Field f: classFile.fields) {
   350             writeField(f);
   351         }
   352     }
   354     protected void writeField(Field f) {
   355         if (!options.checkAccess(f.access_flags))
   356             return;
   358         AccessFlags flags = f.access_flags;
   359         writeModifiers(flags.getFieldModifiers());
   360         Signature_attribute sigAttr = getSignature(f.attributes);
   361         if (sigAttr == null)
   362             print(getJavaFieldType(f.descriptor));
   363         else {
   364             try {
   365                 Type t = sigAttr.getParsedSignature().getType(constant_pool);
   366                 print(getJavaName(t.toString()));
   367             } catch (ConstantPoolException e) {
   368                 // report error?
   369                 // fall back on non-generic descriptor
   370                 print(getJavaFieldType(f.descriptor));
   371             }
   372         }
   373         print(" ");
   374         print(getFieldName(f));
   375         if (options.showConstants && !options.compat) { // BUG 4111861 print static final field contents
   376             Attribute a = f.attributes.get(Attribute.ConstantValue);
   377             if (a instanceof ConstantValue_attribute) {
   378                 print(" = ");
   379                 ConstantValue_attribute cv = (ConstantValue_attribute) a;
   380                 print(getConstantValue(f.descriptor, cv.constantvalue_index));
   381             }
   382         }
   383         print(";");
   384         println();
   386         indent(+1);
   388         if (options.showDescriptors)
   389             println("descriptor: " + getValue(f.descriptor));
   391         if (options.verbose && !options.compat)
   392             writeList("flags: ", flags.getFieldFlags(), "\n");
   394         if (options.showAllAttrs) {
   395             for (Attribute attr: f.attributes)
   396                 attrWriter.write(f, attr, constant_pool);
   397             println();
   398         }
   400         indent(-1);
   402         if (options.showDisassembled || options.showLineAndLocalVariableTables)
   403             println();
   404     }
   406     protected void writeMethods() {
   407         for (Method m: classFile.methods)
   408             writeMethod(m);
   409         setPendingNewline(false);
   410     }
   412     protected void writeMethod(Method m) {
   413         if (!options.checkAccess(m.access_flags))
   414             return;
   416         method = m;
   418         AccessFlags flags = m.access_flags;
   420         Descriptor d;
   421         Type.MethodType methodType;
   422         List<? extends Type> methodExceptions;
   424         Signature_attribute sigAttr = getSignature(m.attributes);
   425         if (sigAttr == null) {
   426             d = m.descriptor;
   427             methodType = null;
   428             methodExceptions = null;
   429         } else {
   430             Signature methodSig = sigAttr.getParsedSignature();
   431             d = methodSig;
   432             try {
   433                 methodType = (Type.MethodType) methodSig.getType(constant_pool);
   434                 methodExceptions = methodType.throwsTypes;
   435                 if (methodExceptions != null && methodExceptions.isEmpty())
   436                     methodExceptions = null;
   437             } catch (ConstantPoolException e) {
   438                 // report error?
   439                 // fall back on standard descriptor
   440                 methodType = null;
   441                 methodExceptions = null;
   442             }
   443         }
   445         writeModifiers(flags.getMethodModifiers());
   446         if (methodType != null) {
   447             print(new JavaTypePrinter(false).printTypeArgs(methodType.typeParamTypes));
   448         }
   449         if (getName(m).equals("<init>")) {
   450             print(getJavaName(classFile));
   451             print(getJavaParameterTypes(d, flags));
   452         } else if (getName(m).equals("<clinit>")) {
   453             print("{}");
   454         } else {
   455             print(getJavaReturnType(d));
   456             print(" ");
   457             print(getName(m));
   458             print(getJavaParameterTypes(d, flags));
   459         }
   461         Attribute e_attr = m.attributes.get(Attribute.Exceptions);
   462         if (e_attr != null) { // if there are generic exceptions, there must be erased exceptions
   463             if (e_attr instanceof Exceptions_attribute) {
   464                 Exceptions_attribute exceptions = (Exceptions_attribute) e_attr;
   465                 print(" throws ");
   466                 if (methodExceptions != null) { // use generic list if available
   467                     writeList("", methodExceptions, "");
   468                 } else {
   469                     for (int i = 0; i < exceptions.number_of_exceptions; i++) {
   470                         if (i > 0)
   471                             print(", ");
   472                         print(getJavaException(exceptions, i));
   473                     }
   474                 }
   475             } else {
   476                 report("Unexpected or invalid value for Exceptions attribute");
   477             }
   478         }
   480         println(";");
   482         indent(+1);
   484         if (options.showDescriptors) {
   485             println("descriptor: " + getValue(m.descriptor));
   486         }
   488         if (options.verbose && !options.compat) {
   489             writeList("flags: ", flags.getMethodFlags(), "\n");
   490         }
   492         Code_attribute code = null;
   493         Attribute c_attr = m.attributes.get(Attribute.Code);
   494         if (c_attr != null) {
   495             if (c_attr instanceof Code_attribute)
   496                 code = (Code_attribute) c_attr;
   497             else
   498                 report("Unexpected or invalid value for Code attribute");
   499         }
   501         if (options.showDisassembled && !options.showAllAttrs) {
   502             if (code != null) {
   503                 println("Code:");
   504                 codeWriter.writeInstrs(code);
   505                 codeWriter.writeExceptionTable(code);
   506             }
   507         }
   509         if (options.showLineAndLocalVariableTables) {
   510             if (code != null) {
   511                 attrWriter.write(code, code.attributes.get(Attribute.LineNumberTable), constant_pool);
   512                 attrWriter.write(code, code.attributes.get(Attribute.LocalVariableTable), constant_pool);
   513             }
   514         }
   516         if (options.showAllAttrs) {
   517             Attribute[] attrs = m.attributes.attrs;
   518             for (Attribute attr: attrs)
   519                 attrWriter.write(m, attr, constant_pool);
   520         }
   522         indent(-1);
   524         // set pendingNewline to write a newline before the next method (if any)
   525         // if a separator is desired
   526         setPendingNewline(
   527                 options.showDisassembled ||
   528                 options.showAllAttrs ||
   529                 options.showDescriptors ||
   530                 options.showLineAndLocalVariableTables ||
   531                 options.verbose);
   532     }
   534     void writeModifiers(Collection<String> items) {
   535         for (Object item: items) {
   536             print(item);
   537             print(" ");
   538         }
   539     }
   541     void writeList(String prefix, Collection<?> items, String suffix) {
   542         print(prefix);
   543         String sep = "";
   544         for (Object item: items) {
   545             print(sep);
   546             print(item);
   547             sep = ", ";
   548         }
   549         print(suffix);
   550     }
   552     void writeListIfNotEmpty(String prefix, List<?> items, String suffix) {
   553         if (items != null && items.size() > 0)
   554             writeList(prefix, items, suffix);
   555     }
   557     Signature_attribute getSignature(Attributes attributes) {
   558         if (options.compat) // javap does not recognize recent attributes
   559             return null;
   560         return (Signature_attribute) attributes.get(Attribute.Signature);
   561     }
   563     String adjustVarargs(AccessFlags flags, String params) {
   564         if (flags.is(ACC_VARARGS) && !options.compat) {
   565             int i = params.lastIndexOf("[]");
   566             if (i > 0)
   567                 return params.substring(0, i) + "..." + params.substring(i+2);
   568         }
   570         return params;
   571     }
   573     String getJavaName(ClassFile cf) {
   574         try {
   575             return getJavaName(cf.getName());
   576         } catch (ConstantPoolException e) {
   577             return report(e);
   578         }
   579     }
   581     String getJavaSuperclassName(ClassFile cf) {
   582         try {
   583             return getJavaName(cf.getSuperclassName());
   584         } catch (ConstantPoolException e) {
   585             return report(e);
   586         }
   587     }
   589     String getJavaInterfaceName(ClassFile cf, int index) {
   590         try {
   591             return getJavaName(cf.getInterfaceName(index));
   592         } catch (ConstantPoolException e) {
   593             return report(e);
   594         }
   595     }
   597     String getJavaFieldType(Descriptor d) {
   598         try {
   599             return getJavaName(d.getFieldType(constant_pool));
   600         } catch (ConstantPoolException e) {
   601             return report(e);
   602         } catch (DescriptorException e) {
   603             return report(e);
   604         }
   605     }
   607     String getJavaReturnType(Descriptor d) {
   608         try {
   609             return getJavaName(d.getReturnType(constant_pool));
   610         } catch (ConstantPoolException e) {
   611             return report(e);
   612         } catch (DescriptorException e) {
   613             return report(e);
   614         }
   615     }
   617     String getJavaParameterTypes(Descriptor d, AccessFlags flags) {
   618         try {
   619             return getJavaName(adjustVarargs(flags, d.getParameterTypes(constant_pool)));
   620         } catch (ConstantPoolException e) {
   621             return report(e);
   622         } catch (DescriptorException e) {
   623             return report(e);
   624         }
   625     }
   627     String getJavaException(Exceptions_attribute attr, int index) {
   628         try {
   629             return getJavaName(attr.getException(index, constant_pool));
   630         } catch (ConstantPoolException e) {
   631             return report(e);
   632         }
   633     }
   635     String getValue(Descriptor d) {
   636         try {
   637             return d.getValue(constant_pool);
   638         } catch (ConstantPoolException e) {
   639             return report(e);
   640         }
   641     }
   643     String getFieldName(Field f) {
   644         try {
   645             return f.getName(constant_pool);
   646         } catch (ConstantPoolException e) {
   647             return report(e);
   648         }
   649     }
   651     String getName(Method m) {
   652         try {
   653             return m.getName(constant_pool);
   654         } catch (ConstantPoolException e) {
   655             return report(e);
   656         }
   657     }
   659     static String getJavaName(String name) {
   660         return name.replace('/', '.');
   661     }
   663     String getSourceFile(SourceFile_attribute attr) {
   664         try {
   665             return attr.getSourceFile(constant_pool);
   666         } catch (ConstantPoolException e) {
   667             return report(e);
   668         }
   669     }
   671     /**
   672      * Get the value of an entry in the constant pool as a Java constant.
   673      * Characters and booleans are represented by CONSTANT_Intgere entries.
   674      * Character and string values are processed to escape characters outside
   675      * the basic printable ASCII set.
   676      * @param d the descriptor, giving the expected type of the constant
   677      * @param index the index of the value in the constant pool
   678      * @return a printable string containing the value of the constant.
   679      */
   680     String getConstantValue(Descriptor d, int index) {
   681         try {
   682             ConstantPool.CPInfo cpInfo = constant_pool.get(index);
   684             switch (cpInfo.getTag()) {
   685                 case ConstantPool.CONSTANT_Integer: {
   686                     ConstantPool.CONSTANT_Integer_info info =
   687                             (ConstantPool.CONSTANT_Integer_info) cpInfo;
   688                     String t = d.getValue(constant_pool);
   689                     if (t.equals("C")) { // character
   690                         return getConstantCharValue((char) info.value);
   691                     } else if (t.equals("Z")) { // boolean
   692                         return String.valueOf(info.value == 1);
   693                     } else { // other: assume integer
   694                         return String.valueOf(info.value);
   695                     }
   696                 }
   698                 case ConstantPool.CONSTANT_String: {
   699                     ConstantPool.CONSTANT_String_info info =
   700                             (ConstantPool.CONSTANT_String_info) cpInfo;
   701                     return getConstantStringValue(info.getString());
   702                 }
   704                 default:
   705                     return constantWriter.stringValue(cpInfo);
   706             }
   707         } catch (ConstantPoolException e) {
   708             return "#" + index;
   709         }
   710     }
   712     private String getConstantCharValue(char c) {
   713         StringBuilder sb = new StringBuilder();
   714         sb.append('\'');
   715         sb.append(esc(c, '\''));
   716         sb.append('\'');
   717         return sb.toString();
   718     }
   720     private String getConstantStringValue(String s) {
   721         StringBuilder sb = new StringBuilder();
   722         sb.append("\"");
   723         for (int i = 0; i < s.length(); i++) {
   724             sb.append(esc(s.charAt(i), '"'));
   725         }
   726         sb.append("\"");
   727         return sb.toString();
   728     }
   730     private String esc(char c, char quote) {
   731         if (32 <= c && c <= 126 && c != quote)
   732             return String.valueOf(c);
   733         else switch (c) {
   734             case '\b': return "\\b";
   735             case '\n': return "\\n";
   736             case '\t': return "\\t";
   737             case '\f': return "\\f";
   738             case '\r': return "\\r";
   739             case '\\': return "\\\\";
   740             case '\'': return "\\'";
   741             case '\"': return "\\\"";
   742             default:   return String.format("\\u%04x", (int) c);
   743         }
   744     }
   746     private Options options;
   747     private AttributeWriter attrWriter;
   748     private CodeWriter codeWriter;
   749     private ConstantWriter constantWriter;
   750     private ClassFile classFile;
   751     private URI uri;
   752     private long lastModified;
   753     private String digestName;
   754     private byte[] digest;
   755     private int size;
   756     private ConstantPool constant_pool;
   757     private Method method;
   758 }

mercurial