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