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