1 /* 2 * Javassist, a Java-bytecode translator toolkit. 3 * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved. 4 * 5 * The contents of this file are subject to the Mozilla Public License Version 6 * 1.1 (the "License"); you may not use this file except in compliance with 7 * the License. Alternatively, the contents of this file may be used under 8 * the terms of the GNU Lesser General Public License Version 2.1 or later, 9 * or the Apache License Version 2.0. 10 * 11 * Software distributed under the License is distributed on an "AS IS" basis, 12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 13 * for the specific language governing rights and limitations under the 14 * License. 15 */ 16 17 package javassist.bytecode; 18 19 import java.io.DataInputStream; 20 import java.io.DataOutputStream; 21 import java.io.IOException; 22 import java.util.ArrayList; 23 import java.util.Collection; 24 import java.util.List; 25 import java.util.ListIterator; 26 import java.util.Map; 27 28 import javassist.CannotCompileException; 29 30 /** 31 * <code>ClassFile</code> represents a Java <code>.class</code> file, which 32 * consists of a constant pool, methods, fields, and attributes. 33 * 34 * <p>For example,</p> 35 * <blockquote><pre> 36 * ClassFile cf = new ClassFile(false, "test.Foo", null); 37 * cf.setInterfaces(new String[] { "java.lang.Cloneable" }); 38 * 39 * FieldInfo f = new FieldInfo(cf.getConstPool(), "width", "I"); 40 * f.setAccessFlags(AccessFlag.PUBLIC); 41 * cf.addField(f); 42 * 43 * cf.write(new DataOutputStream(new FileOutputStream("Foo.class"))); 44 * </pre></blockquote> 45 * <p>This code generates a class file <code>Foo.class</code> for the following class:</p> 46 * <blockquote><pre> 47 * package test; 48 * class Foo implements Cloneable { 49 * public int width; 50 * } 51 * </pre></blockquote> 52 * 53 * @see FieldInfo 54 * @see MethodInfo 55 * @see ClassFileWriter 56 * @see javassist.CtClass#getClassFile() 57 * @see javassist.ClassPool#makeClass(ClassFile) 58 */ 59 public final class ClassFile { 60 int major, minor; // version number 61 ConstPool constPool; 62 int thisClass; 63 int accessFlags; 64 int superClass; 65 int[] interfaces; 66 List<FieldInfo> fields; 67 List<MethodInfo> methods; 68 List<AttributeInfo> attributes; 69 String thisclassname; // not JVM-internal name 70 String[] cachedInterfaces; 71 String cachedSuperclass; 72 73 /** 74 * The major version number of class files 75 * for JDK 1.1. 76 */ 77 public static final int JAVA_1 = 45; 78 79 /** 80 * The major version number of class files 81 * for JDK 1.2. 82 */ 83 public static final int JAVA_2 = 46; 84 85 /** 86 * The major version number of class files 87 * for JDK 1.3. 88 */ 89 public static final int JAVA_3 = 47; 90 91 /** 92 * The major version number of class files 93 * for JDK 1.4. 94 */ 95 public static final int JAVA_4 = 48; 96 97 /** 98 * The major version number of class files 99 * for JDK 1.5. 100 */ 101 public static final int JAVA_5 = 49; 102 103 /** 104 * The major version number of class files 105 * for JDK 1.6. 106 */ 107 public static final int JAVA_6 = 50; 108 109 /** 110 * The major version number of class files 111 * for JDK 1.7. 112 */ 113 public static final int JAVA_7 = 51; 114 115 /** 116 * The major version number of class files 117 * for JDK 1.8. 118 */ 119 public static final int JAVA_8 = 52; 120 121 /** 122 * The major version number of class files 123 * for JDK 1.9. 124 */ 125 public static final int JAVA_9 = 53; 126 127 /** 128 * The major version number of class files 129 * for JDK 10. 130 */ 131 public static final int JAVA_10 = 54; 132 133 /** 134 * The major version number of class files 135 * for JDK 11. 136 */ 137 public static final int JAVA_11 = 55; 138 139 /** 140 * The major version number of class files created 141 * from scratch. The default value is 47 (JDK 1.3). 142 * It is 49 (JDK 1.5) 143 * if the JVM supports <code>java.lang.StringBuilder</code>. 144 * It is 50 (JDK 1.6) 145 * if the JVM supports <code>java.util.zip.DeflaterInputStream</code>. 146 * It is 51 (JDK 1.7) 147 * if the JVM supports <code>java.lang.invoke.CallSite</code>. 148 * It is 52 (JDK 1.8) 149 * if the JVM supports <code>java.util.function.Function</code>. 150 * It is 53 (JDK 1.9) 151 * if the JVM supports <code>java.lang.reflect.Module</code>. 152 * It is 54 (JDK 10) 153 * if the JVM supports <code>java.util.List.copyOf(Collection)</code>. 154 * It is 55 (JDK 11) 155 * if the JVM supports <code>java.util.Optional.isEmpty()</code>. 156 */ 157 public static final int MAJOR_VERSION; 158 159 static { 160 int ver = JAVA_3; 161 try { 162 Class.forName("java.lang.StringBuilder"); 163 ver = JAVA_5; 164 Class.forName("java.util.zip.DeflaterInputStream"); 165 ver = JAVA_6; 166 Class.forName("java.lang.invoke.CallSite", false, ClassLoader.getSystemClassLoader()); 167 ver = JAVA_7; 168 Class.forName("java.util.function.Function"); 169 ver = JAVA_8; 170 Class.forName("java.lang.Module"); 171 ver = JAVA_9; 172 List.class.getMethod("copyOf", Collection.class); 173 ver = JAVA_10; 174 Class.forName("java.util.Optional").getMethod("isEmpty"); 175 ver = JAVA_11; 176 } 177 catch (Throwable t) {} 178 MAJOR_VERSION = ver; 179 } 180 181 /** 182 * Constructs a class file from a byte stream. 183 */ ClassFile(DataInputStream in)184 public ClassFile(DataInputStream in) throws IOException { 185 read(in); 186 } 187 188 /** 189 * Constructs a class file including no members. 190 * 191 * @param isInterface 192 * true if this is an interface. false if this is a class. 193 * @param classname 194 * a fully-qualified class name 195 * @param superclass 196 * a fully-qualified super class name or null. 197 */ ClassFile(boolean isInterface, String classname, String superclass)198 public ClassFile(boolean isInterface, String classname, String superclass) { 199 major = MAJOR_VERSION; 200 minor = 0; // JDK 1.3 or later 201 constPool = new ConstPool(classname); 202 thisClass = constPool.getThisClassInfo(); 203 if (isInterface) 204 accessFlags = AccessFlag.INTERFACE | AccessFlag.ABSTRACT; 205 else 206 accessFlags = AccessFlag.SUPER; 207 208 initSuperclass(superclass); 209 interfaces = null; 210 fields = new ArrayList<FieldInfo>(); 211 methods = new ArrayList<MethodInfo>(); 212 thisclassname = classname; 213 214 attributes = new ArrayList<AttributeInfo>(); 215 attributes.add(new SourceFileAttribute(constPool, 216 getSourcefileName(thisclassname))); 217 } 218 initSuperclass(String superclass)219 private void initSuperclass(String superclass) { 220 if (superclass != null) { 221 this.superClass = constPool.addClassInfo(superclass); 222 cachedSuperclass = superclass; 223 } 224 else { 225 this.superClass = constPool.addClassInfo("java.lang.Object"); 226 cachedSuperclass = "java.lang.Object"; 227 } 228 } 229 getSourcefileName(String qname)230 private static String getSourcefileName(String qname) { 231 return qname.replaceAll("^.*\\.","") + ".java"; 232 } 233 234 /** 235 * Eliminates dead constant pool items. If a method or a field is removed, 236 * the constant pool items used by that method/field become dead items. This 237 * method recreates a constant pool. 238 */ compact()239 public void compact() { 240 ConstPool cp = compact0(); 241 for (MethodInfo minfo:methods) 242 minfo.compact(cp); 243 244 for (FieldInfo finfo:fields) 245 finfo.compact(cp); 246 247 attributes = AttributeInfo.copyAll(attributes, cp); 248 constPool = cp; 249 } 250 compact0()251 private ConstPool compact0() { 252 ConstPool cp = new ConstPool(thisclassname); 253 thisClass = cp.getThisClassInfo(); 254 String sc = getSuperclass(); 255 if (sc != null) 256 superClass = cp.addClassInfo(getSuperclass()); 257 258 if (interfaces != null) 259 for (int i = 0; i < interfaces.length; ++i) 260 interfaces[i] 261 = cp.addClassInfo(constPool.getClassInfo(interfaces[i])); 262 263 return cp; 264 } 265 266 /** 267 * Discards all attributes, associated with both the class file and the 268 * members such as a code attribute and exceptions attribute. The unused 269 * constant pool entries are also discarded (a new packed constant pool is 270 * constructed). 271 */ prune()272 public void prune() { 273 ConstPool cp = compact0(); 274 List<AttributeInfo> newAttributes = new ArrayList<AttributeInfo>(); 275 AttributeInfo invisibleAnnotations 276 = getAttribute(AnnotationsAttribute.invisibleTag); 277 if (invisibleAnnotations != null) { 278 invisibleAnnotations = invisibleAnnotations.copy(cp, null); 279 newAttributes.add(invisibleAnnotations); 280 } 281 282 AttributeInfo visibleAnnotations 283 = getAttribute(AnnotationsAttribute.visibleTag); 284 if (visibleAnnotations != null) { 285 visibleAnnotations = visibleAnnotations.copy(cp, null); 286 newAttributes.add(visibleAnnotations); 287 } 288 289 AttributeInfo signature 290 = getAttribute(SignatureAttribute.tag); 291 if (signature != null) { 292 signature = signature.copy(cp, null); 293 newAttributes.add(signature); 294 } 295 296 for (MethodInfo minfo:methods) 297 minfo.prune(cp); 298 299 for (FieldInfo finfo:fields) 300 finfo.prune(cp); 301 302 attributes = newAttributes; 303 constPool = cp; 304 } 305 306 /** 307 * Returns a constant pool table. 308 */ getConstPool()309 public ConstPool getConstPool() { 310 return constPool; 311 } 312 313 /** 314 * Returns true if this is an interface. 315 */ isInterface()316 public boolean isInterface() { 317 return (accessFlags & AccessFlag.INTERFACE) != 0; 318 } 319 320 /** 321 * Returns true if this is a final class or interface. 322 */ isFinal()323 public boolean isFinal() { 324 return (accessFlags & AccessFlag.FINAL) != 0; 325 } 326 327 /** 328 * Returns true if this is an abstract class or an interface. 329 */ isAbstract()330 public boolean isAbstract() { 331 return (accessFlags & AccessFlag.ABSTRACT) != 0; 332 } 333 334 /** 335 * Returns access flags. 336 * 337 * @see javassist.bytecode.AccessFlag 338 */ getAccessFlags()339 public int getAccessFlags() { 340 return accessFlags; 341 } 342 343 /** 344 * Changes access flags. 345 * 346 * @see javassist.bytecode.AccessFlag 347 */ setAccessFlags(int acc)348 public void setAccessFlags(int acc) { 349 if ((acc & AccessFlag.INTERFACE) == 0) 350 acc |= AccessFlag.SUPER; 351 352 accessFlags = acc; 353 } 354 355 /** 356 * Returns access and property flags of this nested class. 357 * This method returns -1 if the class is not a nested class. 358 * 359 * <p>The returned value is obtained from <code>inner_class_access_flags</code> 360 * of the entry representing this nested class itself 361 * in <code>InnerClasses_attribute</code>. 362 */ getInnerAccessFlags()363 public int getInnerAccessFlags() { 364 InnerClassesAttribute ica 365 = (InnerClassesAttribute)getAttribute(InnerClassesAttribute.tag); 366 if (ica == null) 367 return -1; 368 369 String name = getName(); 370 int n = ica.tableLength(); 371 for (int i = 0; i < n; ++i) 372 if (name.equals(ica.innerClass(i))) 373 return ica.accessFlags(i); 374 375 return -1; 376 } 377 378 /** 379 * Returns the class name. 380 */ getName()381 public String getName() { 382 return thisclassname; 383 } 384 385 /** 386 * Sets the class name. This method substitutes the new name for all 387 * occurrences of the old class name in the class file. 388 */ setName(String name)389 public void setName(String name) { 390 renameClass(thisclassname, name); 391 } 392 393 /** 394 * Returns the super class name. 395 */ getSuperclass()396 public String getSuperclass() { 397 if (cachedSuperclass == null) 398 cachedSuperclass = constPool.getClassInfo(superClass); 399 400 return cachedSuperclass; 401 } 402 403 /** 404 * Returns the index of the constant pool entry representing the super 405 * class. 406 */ getSuperclassId()407 public int getSuperclassId() { 408 return superClass; 409 } 410 411 /** 412 * Sets the super class. 413 * 414 * <p> 415 * The new super class should inherit from the old super class. 416 * This method modifies constructors so that they call constructors declared 417 * in the new super class. 418 */ setSuperclass(String superclass)419 public void setSuperclass(String superclass) throws CannotCompileException { 420 if (superclass == null) 421 superclass = "java.lang.Object"; 422 423 try { 424 this.superClass = constPool.addClassInfo(superclass); 425 for (MethodInfo minfo:methods) 426 minfo.setSuperclass(superclass); 427 } 428 catch (BadBytecode e) { 429 throw new CannotCompileException(e); 430 } 431 cachedSuperclass = superclass; 432 } 433 434 /** 435 * Replaces all occurrences of a class name in the class file. 436 * 437 * <p> 438 * If class X is substituted for class Y in the class file, X and Y must 439 * have the same signature. If Y provides a method m(), X must provide it 440 * even if X inherits m() from the super class. If this fact is not 441 * guaranteed, the bytecode verifier may cause an error. 442 * 443 * @param oldname 444 * the replaced class name 445 * @param newname 446 * the substituted class name 447 */ renameClass(String oldname, String newname)448 public final void renameClass(String oldname, String newname) { 449 if (oldname.equals(newname)) 450 return; 451 452 if (oldname.equals(thisclassname)) 453 thisclassname = newname; 454 455 oldname = Descriptor.toJvmName(oldname); 456 newname = Descriptor.toJvmName(newname); 457 constPool.renameClass(oldname, newname); 458 459 AttributeInfo.renameClass(attributes, oldname, newname); 460 for (MethodInfo minfo :methods) { 461 String desc = minfo.getDescriptor(); 462 minfo.setDescriptor(Descriptor.rename(desc, oldname, newname)); 463 AttributeInfo.renameClass(minfo.getAttributes(), oldname, newname); 464 } 465 466 for (FieldInfo finfo:fields) { 467 String desc = finfo.getDescriptor(); 468 finfo.setDescriptor(Descriptor.rename(desc, oldname, newname)); 469 AttributeInfo.renameClass(finfo.getAttributes(), oldname, newname); 470 } 471 } 472 473 /** 474 * Replaces all occurrences of several class names in the class file. 475 * 476 * @param classnames 477 * specifies which class name is replaced with which new name. 478 * Class names must be described with the JVM-internal 479 * representation like <code>java/lang/Object</code>. 480 * @see #renameClass(String,String) 481 */ renameClass(Map<String,String> classnames)482 public final void renameClass(Map<String,String> classnames) { 483 String jvmNewThisName = classnames.get(Descriptor 484 .toJvmName(thisclassname)); 485 if (jvmNewThisName != null) 486 thisclassname = Descriptor.toJavaName(jvmNewThisName); 487 488 constPool.renameClass(classnames); 489 490 AttributeInfo.renameClass(attributes, classnames); 491 for (MethodInfo minfo:methods) { 492 String desc = minfo.getDescriptor(); 493 minfo.setDescriptor(Descriptor.rename(desc, classnames)); 494 AttributeInfo.renameClass(minfo.getAttributes(), classnames); 495 } 496 497 for (FieldInfo finfo:fields) { 498 String desc = finfo.getDescriptor(); 499 finfo.setDescriptor(Descriptor.rename(desc, classnames)); 500 AttributeInfo.renameClass(finfo.getAttributes(), classnames); 501 } 502 } 503 504 /** 505 * Internal-use only. 506 * <code>CtClass.getRefClasses()</code> calls this method. 507 */ getRefClasses(Map<String,String> classnames)508 public final void getRefClasses(Map<String,String> classnames) { 509 constPool.renameClass(classnames); 510 511 AttributeInfo.getRefClasses(attributes, classnames); 512 for (MethodInfo minfo:methods) { 513 String desc = minfo.getDescriptor(); 514 Descriptor.rename(desc, classnames); 515 AttributeInfo.getRefClasses(minfo.getAttributes(), classnames); 516 } 517 518 for (FieldInfo finfo:fields) { 519 String desc = finfo.getDescriptor(); 520 Descriptor.rename(desc, classnames); 521 AttributeInfo.getRefClasses(finfo.getAttributes(), classnames); 522 } 523 } 524 525 /** 526 * Returns the names of the interfaces implemented by the class. 527 * The returned array is read only. 528 */ getInterfaces()529 public String[] getInterfaces() { 530 if (cachedInterfaces != null) 531 return cachedInterfaces; 532 533 String[] rtn = null; 534 if (interfaces == null) 535 rtn = new String[0]; 536 else { 537 String[] list = new String[interfaces.length]; 538 for (int i = 0; i < interfaces.length; ++i) 539 list[i] = constPool.getClassInfo(interfaces[i]); 540 541 rtn = list; 542 } 543 544 cachedInterfaces = rtn; 545 return rtn; 546 } 547 548 /** 549 * Sets the interfaces. 550 * 551 * @param nameList 552 * the names of the interfaces. 553 */ setInterfaces(String[] nameList)554 public void setInterfaces(String[] nameList) { 555 cachedInterfaces = null; 556 if (nameList != null) { 557 interfaces = new int[nameList.length]; 558 for (int i = 0; i < nameList.length; ++i) 559 interfaces[i] = constPool.addClassInfo(nameList[i]); 560 } 561 } 562 563 /** 564 * Appends an interface to the interfaces implemented by the class. 565 */ addInterface(String name)566 public void addInterface(String name) { 567 cachedInterfaces = null; 568 int info = constPool.addClassInfo(name); 569 if (interfaces == null) { 570 interfaces = new int[1]; 571 interfaces[0] = info; 572 } 573 else { 574 int n = interfaces.length; 575 int[] newarray = new int[n + 1]; 576 System.arraycopy(interfaces, 0, newarray, 0, n); 577 newarray[n] = info; 578 interfaces = newarray; 579 } 580 } 581 582 /** 583 * Returns all the fields declared in the class. 584 * 585 * @return a list of <code>FieldInfo</code>. 586 * @see FieldInfo 587 */ getFields()588 public List<FieldInfo> getFields() { 589 return fields; 590 } 591 592 /** 593 * Appends a field to the class. 594 * 595 * @throws DuplicateMemberException when the field is already included. 596 */ addField(FieldInfo finfo)597 public void addField(FieldInfo finfo) throws DuplicateMemberException { 598 testExistingField(finfo.getName(), finfo.getDescriptor()); 599 fields.add(finfo); 600 } 601 602 /** 603 * Just appends a field to the class. 604 * It does not check field duplication. 605 * Use this method only when minimizing performance overheads 606 * is seriously required. 607 * 608 * @since 3.13 609 */ addField2(FieldInfo finfo)610 public final void addField2(FieldInfo finfo) { 611 fields.add(finfo); 612 } 613 testExistingField(String name, String descriptor)614 private void testExistingField(String name, String descriptor) 615 throws DuplicateMemberException { 616 for (FieldInfo minfo:fields) 617 if (minfo.getName().equals(name)) 618 throw new DuplicateMemberException("duplicate field: " + name); 619 } 620 621 /** 622 * Returns all the methods declared in the class. 623 * 624 * @return a list of <code>MethodInfo</code>. 625 * @see MethodInfo 626 */ getMethods()627 public List<MethodInfo> getMethods() { 628 return methods; 629 } 630 631 /** 632 * Returns the method with the specified name. If there are multiple methods 633 * with that name, this method returns one of them. 634 * 635 * @return null if no such method is found. 636 */ getMethod(String name)637 public MethodInfo getMethod(String name) { 638 for (MethodInfo minfo:methods) 639 if (minfo.getName().equals(name)) 640 return minfo; 641 return null; 642 } 643 644 /** 645 * Returns a static initializer (class initializer), or null if it does not 646 * exist. 647 */ getStaticInitializer()648 public MethodInfo getStaticInitializer() { 649 return getMethod(MethodInfo.nameClinit); 650 } 651 652 /** 653 * Appends a method to the class. 654 * If there is a bridge method with the same name and signature, 655 * then the bridge method is removed before a new method is added. 656 * 657 * @throws DuplicateMemberException when the method is already included. 658 */ addMethod(MethodInfo minfo)659 public void addMethod(MethodInfo minfo) throws DuplicateMemberException { 660 testExistingMethod(minfo); 661 methods.add(minfo); 662 } 663 664 /** 665 * Just appends a method to the class. 666 * It does not check method duplication or remove a bridge method. 667 * Use this method only when minimizing performance overheads 668 * is seriously required. 669 * 670 * @since 3.13 671 */ addMethod2(MethodInfo minfo)672 public final void addMethod2(MethodInfo minfo) { 673 methods.add(minfo); 674 } 675 testExistingMethod(MethodInfo newMinfo)676 private void testExistingMethod(MethodInfo newMinfo) 677 throws DuplicateMemberException 678 { 679 String name = newMinfo.getName(); 680 String descriptor = newMinfo.getDescriptor(); 681 ListIterator<MethodInfo> it = methods.listIterator(0); 682 while (it.hasNext()) 683 if (isDuplicated(newMinfo, name, descriptor, it.next(), it)) 684 throw new DuplicateMemberException("duplicate method: " + name 685 + " in " + this.getName()); 686 } 687 isDuplicated(MethodInfo newMethod, String newName, String newDesc, MethodInfo minfo, ListIterator<MethodInfo> it)688 private static boolean isDuplicated(MethodInfo newMethod, String newName, 689 String newDesc, MethodInfo minfo, 690 ListIterator<MethodInfo> it) 691 { 692 if (!minfo.getName().equals(newName)) 693 return false; 694 695 String desc = minfo.getDescriptor(); 696 if (!Descriptor.eqParamTypes(desc, newDesc)) 697 return false; 698 699 if (desc.equals(newDesc)) { 700 if (notBridgeMethod(minfo)) 701 return true; 702 // if the bridge method with the same signature 703 // already exists, replace it. 704 it.remove(); 705 return false; 706 } 707 return false; 708 // return notBridgeMethod(minfo) && notBridgeMethod(newMethod); 709 } 710 711 /* For a bridge method, see Sec. 15.12.4.5 of JLS 3rd Ed. 712 */ notBridgeMethod(MethodInfo minfo)713 private static boolean notBridgeMethod(MethodInfo minfo) { 714 return (minfo.getAccessFlags() & AccessFlag.BRIDGE) == 0; 715 } 716 717 /** 718 * Returns all the attributes. The returned <code>List</code> object 719 * is shared with this object. If you add a new attribute to the list, 720 * the attribute is also added to the classs file represented by this 721 * object. If you remove an attribute from the list, it is also removed 722 * from the class file. 723 * 724 * @return a list of <code>AttributeInfo</code> objects. 725 * @see AttributeInfo 726 */ getAttributes()727 public List<AttributeInfo> getAttributes() { 728 return attributes; 729 } 730 731 /** 732 * Returns the attribute with the specified name. If there are multiple 733 * attributes with that name, this method returns either of them. It 734 * returns null if the specified attributed is not found. 735 * 736 * <p>An attribute name can be obtained by, for example, 737 * {@link AnnotationsAttribute#visibleTag} or 738 * {@link AnnotationsAttribute#invisibleTag}. 739 * </p> 740 * 741 * @param name attribute name 742 * @see #getAttributes() 743 */ getAttribute(String name)744 public AttributeInfo getAttribute(String name) { 745 for (AttributeInfo ai:attributes) 746 if (ai.getName().equals(name)) 747 return ai; 748 return null; 749 } 750 751 /** 752 * Removes an attribute with the specified name. 753 * 754 * @param name attribute name. 755 * @return the removed attribute or null. 756 * @since 3.21 757 */ removeAttribute(String name)758 public AttributeInfo removeAttribute(String name) { 759 return AttributeInfo.remove(attributes, name); 760 } 761 762 /** 763 * Appends an attribute. If there is already an attribute with the same 764 * name, the new one substitutes for it. 765 * 766 * @see #getAttributes() 767 */ addAttribute(AttributeInfo info)768 public void addAttribute(AttributeInfo info) { 769 AttributeInfo.remove(attributes, info.getName()); 770 attributes.add(info); 771 } 772 773 /** 774 * Returns the source file containing this class. 775 * 776 * @return null if this information is not available. 777 */ getSourceFile()778 public String getSourceFile() { 779 SourceFileAttribute sf 780 = (SourceFileAttribute)getAttribute(SourceFileAttribute.tag); 781 if (sf == null) 782 return null; 783 return sf.getFileName(); 784 } 785 read(DataInputStream in)786 private void read(DataInputStream in) throws IOException { 787 int i, n; 788 int magic = in.readInt(); 789 if (magic != 0xCAFEBABE) 790 throw new IOException("bad magic number: " + Integer.toHexString(magic)); 791 792 minor = in.readUnsignedShort(); 793 major = in.readUnsignedShort(); 794 constPool = new ConstPool(in); 795 accessFlags = in.readUnsignedShort(); 796 thisClass = in.readUnsignedShort(); 797 constPool.setThisClassInfo(thisClass); 798 superClass = in.readUnsignedShort(); 799 n = in.readUnsignedShort(); 800 if (n == 0) 801 interfaces = null; 802 else { 803 interfaces = new int[n]; 804 for (i = 0; i < n; ++i) 805 interfaces[i] = in.readUnsignedShort(); 806 } 807 808 ConstPool cp = constPool; 809 n = in.readUnsignedShort(); 810 fields = new ArrayList<FieldInfo>(); 811 for (i = 0; i < n; ++i) 812 addField2(new FieldInfo(cp, in)); 813 814 n = in.readUnsignedShort(); 815 methods = new ArrayList<MethodInfo>(); 816 for (i = 0; i < n; ++i) 817 addMethod2(new MethodInfo(cp, in)); 818 819 attributes = new ArrayList<AttributeInfo>(); 820 n = in.readUnsignedShort(); 821 for (i = 0; i < n; ++i) 822 addAttribute(AttributeInfo.read(cp, in)); 823 824 thisclassname = constPool.getClassInfo(thisClass); 825 } 826 827 /** 828 * Writes a class file represented by this object into an output stream. 829 */ write(DataOutputStream out)830 public void write(DataOutputStream out) throws IOException { 831 int i, n; 832 833 out.writeInt(0xCAFEBABE); // magic 834 out.writeShort(minor); // minor version 835 out.writeShort(major); // major version 836 constPool.write(out); // constant pool 837 out.writeShort(accessFlags); 838 out.writeShort(thisClass); 839 out.writeShort(superClass); 840 841 if (interfaces == null) 842 n = 0; 843 else 844 n = interfaces.length; 845 846 out.writeShort(n); 847 for (i = 0; i < n; ++i) 848 out.writeShort(interfaces[i]); 849 850 n = fields.size(); 851 out.writeShort(n); 852 for (i = 0; i < n; ++i) { 853 FieldInfo finfo = fields.get(i); 854 finfo.write(out); 855 } 856 857 out.writeShort(methods.size()); 858 for (MethodInfo minfo:methods) 859 minfo.write(out); 860 861 out.writeShort(attributes.size()); 862 AttributeInfo.writeAll(attributes, out); 863 } 864 865 /** 866 * Get the Major version. 867 * 868 * @return the major version 869 */ getMajorVersion()870 public int getMajorVersion() { 871 return major; 872 } 873 874 /** 875 * Set the major version. 876 * 877 * @param major 878 * the major version 879 */ setMajorVersion(int major)880 public void setMajorVersion(int major) { 881 this.major = major; 882 } 883 884 /** 885 * Get the minor version. 886 * 887 * @return the minor version 888 */ getMinorVersion()889 public int getMinorVersion() { 890 return minor; 891 } 892 893 /** 894 * Set the minor version. 895 * 896 * @param minor 897 * the minor version 898 */ setMinorVersion(int minor)899 public void setMinorVersion(int minor) { 900 this.minor = minor; 901 } 902 903 /** 904 * Sets the major and minor version to Java 5. 905 * 906 * If the major version is older than 49, Java 5 907 * extensions such as annotations are ignored 908 * by the JVM. 909 */ setVersionToJava5()910 public void setVersionToJava5() { 911 this.major = 49; 912 this.minor = 0; 913 } 914 } 915