1 52 53 package com.go.trove.classfile; 54 55 import java.lang.reflect.*; 56 import java.util.Set ; 57 import java.util.HashSet ; 58 import java.util.List ; 59 import java.util.ArrayList ; 60 import java.util.Map ; 61 import java.util.HashMap ; 62 import java.io.*; 63 64 76 public class ClassFile { 77 private static final int MAGIC = 0xCAFEBABE; 78 private static final int JDK1_1_MAJOR_VERSION = 45; 79 private static final int JDK1_1_MINOR_VERSION = 3; 80 81 private int mMajorVersion = JDK1_1_MAJOR_VERSION; 82 private int mMinorVersion = JDK1_1_MINOR_VERSION; 83 84 private String mClassName; 85 private String mSuperClassName; 86 private String mInnerClassName; 87 private TypeDescriptor mType; 88 89 private ConstantPool mCp; 90 91 private AccessFlags mAccessFlags; 92 93 private ConstantClassInfo mThisClass; 94 private ConstantClassInfo mSuperClass; 95 96 private List mInterfaces = new ArrayList (2); 98 private Set mInterfaceSet = new HashSet (7); 99 100 private List mFields = new ArrayList (); 102 private List mMethods = new ArrayList (); 103 private List mAttributes = new ArrayList (); 104 105 private SourceFileAttr mSource; 106 107 private List mInnerClasses; 108 private int mAnonymousInnerClassCount = 0; 109 private InnerClassesAttr mInnerClassesAttr; 110 111 private ClassFile mOuterClass; 113 114 124 public ClassFile(String className) { 125 this(className, (String )null); 126 } 127 128 137 public ClassFile(String className, Class superClass) { 138 this(className, superClass.getName()); 139 } 140 141 150 public ClassFile(String className, String superClassName) { 151 if (superClassName == null) { 152 if (!className.equals(Object .class.getName())) { 153 superClassName = Object .class.getName(); 154 } 155 } 156 157 mCp = new ConstantPool(); 158 159 mAccessFlags = new AccessFlags(Modifier.PUBLIC); 161 162 mThisClass = ConstantClassInfo.make(mCp, className); 163 mSuperClass = ConstantClassInfo.make(mCp, superClassName); 164 165 mClassName = className; 166 mSuperClassName = superClassName; 167 } 168 169 172 private ClassFile(ConstantPool cp, AccessFlags accessFlags, 173 ConstantClassInfo thisClass, 174 ConstantClassInfo superClass, 175 ClassFile outerClass) { 176 177 mCp = cp; 178 179 mAccessFlags = accessFlags; 180 181 mThisClass = thisClass; 182 mSuperClass = superClass; 183 184 mClassName = thisClass.getClassName(); 185 if (superClass != null) { 186 mSuperClassName = superClass.getClassName(); 187 } 188 189 mOuterClass = outerClass; 190 } 191 192 public String getClassName() { 193 return mClassName; 194 } 195 196 public String getSuperClassName() { 197 return mSuperClassName; 198 } 199 200 203 public TypeDescriptor getType() { 204 if (mType == null) { 205 mType = new TypeDescriptor(mClassName); 206 } 207 return mType; 208 } 209 210 public AccessFlags getAccessFlags() { 211 return mAccessFlags; 212 } 213 214 217 public String [] getInterfaces() { 218 int size = mInterfaces.size(); 219 String [] names = new String [size]; 220 221 for (int i=0; i<size; i++) { 222 names[i] = ((ConstantClassInfo)mInterfaces.get(i)).getClassName(); 223 } 224 225 return names; 226 } 227 228 231 public FieldInfo[] getFields() { 232 FieldInfo[] fields = new FieldInfo[mFields.size()]; 233 return (FieldInfo[])mFields.toArray(fields); 234 } 235 236 240 public MethodInfo[] getMethods() { 241 int size = mMethods.size(); 242 List methodsOnly = new ArrayList (size); 243 244 for (int i=0; i<size; i++) { 245 MethodInfo method = (MethodInfo)mMethods.get(i); 246 String name = method.getName(); 247 if (!"<init>".equals(name) && !"<clinit>".equals(name)) { 248 methodsOnly.add(method); 249 } 250 } 251 252 MethodInfo[] methodsArray = new MethodInfo[methodsOnly.size()]; 253 return (MethodInfo[])methodsOnly.toArray(methodsArray); 254 } 255 256 259 public MethodInfo[] getConstructors() { 260 int size = mMethods.size(); 261 List ctorsOnly = new ArrayList (size); 262 263 for (int i=0; i<size; i++) { 264 MethodInfo method = (MethodInfo)mMethods.get(i); 265 if ("<init>".equals(method.getName())) { 266 ctorsOnly.add(method); 267 } 268 } 269 270 MethodInfo[] ctorsArray = new MethodInfo[ctorsOnly.size()]; 271 return (MethodInfo[])ctorsOnly.toArray(ctorsArray); 272 } 273 274 278 public MethodInfo getInitializer() { 279 int size = mMethods.size(); 280 281 for (int i=0; i<size; i++) { 282 MethodInfo method = (MethodInfo)mMethods.get(i); 283 if ("<clinit>".equals(method.getName())) { 284 return method; 285 } 286 } 287 288 return null; 289 } 290 291 295 public ClassFile[] getInnerClasses() { 296 if (mInnerClasses == null) { 297 return new ClassFile[0]; 298 } 299 300 ClassFile[] innerClasses = new ClassFile[mInnerClasses.size()]; 301 return (ClassFile[])mInnerClasses.toArray(innerClasses); 302 } 303 304 307 public boolean isInnerClass() { 308 return mOuterClass != null; 309 } 310 311 315 public String getInnerClassName() { 316 return mInnerClassName; 317 } 318 319 324 public ClassFile getOuterClass() { 325 return mOuterClass; 326 } 327 328 333 public int getClassDepth() { 334 int depth = 0; 335 336 ClassFile outer = mOuterClass; 337 while (outer != null) { 338 depth++; 339 outer = outer.mOuterClass; 340 } 341 342 return depth; 343 } 344 345 348 public String getSourceFile() { 349 if (mSource == null) { 350 return null; 351 } 352 else { 353 return mSource.getFileName(); 354 } 355 } 356 357 public boolean isSynthetic() { 358 for (int i = mAttributes.size(); --i >= 0; ) { 359 Object obj = mAttributes.get(i); 360 if (obj instanceof SyntheticAttr) { 361 return true; 362 } 363 } 364 return false; 365 } 366 367 public boolean isDeprecated() { 368 for (int i = mAttributes.size(); --i >= 0; ) { 369 Object obj = mAttributes.get(i); 370 if (obj instanceof DeprecatedAttr) { 371 return true; 372 } 373 } 374 return false; 375 } 376 377 382 public ConstantPool getConstantPool() { 383 return mCp; 384 } 385 386 391 public void addInterface(String interfaceName) { 392 if (!mInterfaceSet.contains(interfaceName)) { 393 mInterfaces.add(ConstantClassInfo.make(mCp, interfaceName)); 394 mInterfaceSet.add(interfaceName); 395 } 396 } 397 398 401 public void addInterface(Class i) { 402 addInterface(i.getName()); 403 } 404 405 408 public FieldInfo addField(AccessFlags flags, 409 String fieldName, 410 TypeDescriptor type) { 411 FieldInfo fi = new FieldInfo(this, flags, fieldName, type); 412 mFields.add(fi); 413 return fi; 414 } 415 416 422 public MethodInfo addMethod(AccessFlags flags, 423 String methodName, 424 TypeDescriptor ret, 425 TypeDescriptor[] params) { 426 MethodDescriptor md = new MethodDescriptor(ret, params); 427 return addMethod(flags, methodName, md); 428 } 429 430 433 public MethodInfo addMethod(AccessFlags flags, 434 String methodName, 435 MethodDescriptor md) { 436 MethodInfo mi = new MethodInfo(this, flags, methodName, md); 437 mMethods.add(mi); 438 return mi; 439 } 440 441 445 public MethodInfo addMethod(Method method) { 446 AccessFlags flags = new AccessFlags(method.getModifiers()); 447 flags.setAbstract(false); 448 449 TypeDescriptor ret = new TypeDescriptor(method.getReturnType()); 450 451 Class [] paramClasses = method.getParameterTypes(); 452 TypeDescriptor[] params = new TypeDescriptor[paramClasses.length]; 453 for (int i=0; i<params.length; i++) { 454 params[i] = new TypeDescriptor(paramClasses[i]); 455 } 456 457 MethodInfo mi = addMethod(flags, method.getName(), ret, params); 458 459 Class [] exceptions = method.getExceptionTypes(); 461 for (int i=0; i<exceptions.length; i++) { 462 mi.addException(exceptions[i].getName()); 463 } 464 465 return mi; 466 } 467 468 473 public MethodInfo addConstructor(AccessFlags flags, 474 TypeDescriptor[] params) { 475 MethodDescriptor md = new MethodDescriptor(null, params); 476 MethodInfo mi = new MethodInfo(this, flags, "<init>", md); 477 mMethods.add(mi); 478 return mi; 479 } 480 481 484 public MethodInfo addInitializer() { 485 MethodDescriptor md = new MethodDescriptor(null, null); 486 AccessFlags af = new AccessFlags(); 487 af.setStatic(true); 488 MethodInfo mi = new MethodInfo(this, af, "<clinit>", md); 489 mMethods.add(mi); 490 return mi; 491 } 492 493 499 public ClassFile addInnerClass(String innerClassName) { 500 return addInnerClass(innerClassName, (String )null); 501 } 502 503 510 public ClassFile addInnerClass(String innerClassName, Class superClass) { 511 return addInnerClass(innerClassName, superClass.getName()); 512 } 513 514 522 public ClassFile addInnerClass(String innerClassName, 523 String superClassName) { 524 String fullInnerClassName; 525 if (innerClassName == null) { 526 fullInnerClassName = 527 mClassName + '$' + (++mAnonymousInnerClassCount); 528 } 529 else { 530 fullInnerClassName = mClassName + '$' + innerClassName; 531 } 532 533 ClassFile inner = new ClassFile(fullInnerClassName, superClassName); 534 AccessFlags access = inner.getAccessFlags(); 535 access.setPrivate(true); 536 access.setStatic(true); 537 inner.mInnerClassName = innerClassName; 538 inner.mOuterClass = this; 539 540 if (mInnerClasses == null) { 541 mInnerClasses = new ArrayList (); 542 } 543 544 mInnerClasses.add(inner); 545 546 if (mInnerClassesAttr == null) { 548 addAttribute(new InnerClassesAttr(mCp)); 549 } 550 551 mInnerClassesAttr.addInnerClass(fullInnerClassName, mClassName, 552 innerClassName, access); 553 554 inner.addAttribute(new InnerClassesAttr(inner.getConstantPool())); 556 inner.mInnerClassesAttr.addInnerClass(fullInnerClassName, mClassName, 557 innerClassName, access); 558 559 return inner; 560 } 561 562 567 public void setSourceFile(String fileName) { 568 addAttribute(new SourceFileAttr(mCp, fileName)); 569 } 570 571 574 public void markSynthetic() { 575 addAttribute(new SyntheticAttr(mCp)); 576 } 577 578 581 public void markDeprecated() { 582 addAttribute(new DeprecatedAttr(mCp)); 583 } 584 585 588 public void addAttribute(Attribute attr) { 589 if (attr instanceof SourceFileAttr) { 590 if (mSource != null) { 591 mAttributes.remove(mSource); 592 } 593 mSource = (SourceFileAttr)attr; 594 } 595 else if (attr instanceof InnerClassesAttr) { 596 if (mInnerClassesAttr != null) { 597 mAttributes.remove(mInnerClassesAttr); 598 } 599 mInnerClassesAttr = (InnerClassesAttr)attr; 600 } 601 602 mAttributes.add(attr); 603 } 604 605 public Attribute[] getAttributes() { 606 Attribute[] attrs = new Attribute[mAttributes.size()]; 607 return (Attribute[])mAttributes.toArray(attrs); 608 } 609 610 616 public void setVersion(int major, int minor) 617 throws IllegalArgumentException { 618 619 if (major != JDK1_1_MAJOR_VERSION || 620 minor != JDK1_1_MINOR_VERSION) { 621 622 throw new IllegalArgumentException ("Version " + major + ", " + 623 minor + " is not supported"); 624 } 625 626 mMajorVersion = major; 627 mMinorVersion = minor; 628 } 629 630 634 public void writeTo(OutputStream out) throws IOException { 635 if (!(out instanceof DataOutput)) { 636 out = new DataOutputStream(out); 637 } 638 639 writeTo((DataOutput)out); 640 641 out.flush(); 642 } 643 644 647 public void writeTo(DataOutput dout) throws IOException { 648 dout.writeInt(MAGIC); 649 dout.writeShort(mMinorVersion); 650 dout.writeShort(mMajorVersion); 651 652 mCp.writeTo(dout); 653 654 int modifier = mAccessFlags.getModifier(); 655 dout.writeShort(modifier | Modifier.SYNCHRONIZED); 656 657 dout.writeShort(mThisClass.getIndex()); 658 if (mSuperClass != null) { 659 dout.writeShort(mSuperClass.getIndex()); 660 } 661 else { 662 dout.writeShort(0); 663 } 664 665 int size = mInterfaces.size(); 666 if (size > 65535) { 667 throw new RuntimeException 668 ("Interfaces count cannot exceed 65535: " + size); 669 } 670 dout.writeShort(size); 671 for (int i=0; i<size; i++) { 672 int index = ((ConstantInfo)mInterfaces.get(i)).getIndex(); 673 dout.writeShort(index); 674 } 675 676 size = mFields.size(); 677 if (size > 65535) { 678 throw new RuntimeException 679 ("Field count cannot exceed 65535: " + size); 680 } 681 dout.writeShort(size); 682 for (int i=0; i<size; i++) { 683 FieldInfo field = (FieldInfo)mFields.get(i); 684 field.writeTo(dout); 685 } 686 687 size = mMethods.size(); 688 if (size > 65535) { 689 throw new RuntimeException 690 ("Method count cannot exceed 65535: " + size); 691 } 692 dout.writeShort(size); 693 for (int i=0; i<size; i++) { 694 MethodInfo method = (MethodInfo)mMethods.get(i); 695 method.writeTo(dout); 696 } 697 698 size = mAttributes.size(); 699 if (size > 65535) { 700 throw new RuntimeException 701 ("Attribute count cannot exceed 65535: " + size); 702 } 703 dout.writeShort(size); 704 for (int i=0; i<size; i++) { 705 Attribute attr = (Attribute)mAttributes.get(i); 706 attr.writeTo(dout); 707 } 708 } 709 710 721 public static ClassFile readFrom(InputStream in) throws IOException { 722 return readFrom(in, null, null); 723 } 724 725 736 public static ClassFile readFrom(DataInput din) throws IOException { 737 return readFrom(din, null, null); 738 } 739 740 756 public static ClassFile readFrom(InputStream in, 757 ClassFileDataLoader loader, 758 AttributeFactory attrFactory) 759 throws IOException 760 { 761 if (!(in instanceof DataInput)) { 762 in = new DataInputStream(in); 763 } 764 return readFrom((DataInput)in, loader, attrFactory); 765 } 766 767 783 public static ClassFile readFrom(DataInput din, 784 ClassFileDataLoader loader, 785 AttributeFactory attrFactory) 786 throws IOException 787 { 788 return readFrom(din, loader, attrFactory, new HashMap (11), null); 789 } 790 791 795 private static ClassFile readFrom(DataInput din, 796 ClassFileDataLoader loader, 797 AttributeFactory attrFactory, 798 Map loadedClassFiles, 799 ClassFile outerClass) 800 throws IOException 801 { 802 int magic = din.readInt(); 803 if (magic != MAGIC) { 804 throw new IOException("Incorrect magic number: 0x" + 805 Integer.toHexString(magic)); 806 } 807 808 int minor = din.readUnsignedShort(); 809 816 817 int major = din.readUnsignedShort(); 818 825 826 ConstantPool cp = ConstantPool.readFrom(din); 827 AccessFlags accessFlags = new AccessFlags(din.readUnsignedShort()); 828 accessFlags.setSynchronized(false); 829 830 int index = din.readUnsignedShort(); 831 ConstantClassInfo thisClass = (ConstantClassInfo)cp.getConstant(index); 832 833 index = din.readUnsignedShort(); 834 ConstantClassInfo superClass = null; 835 if (index > 0) { 836 superClass = (ConstantClassInfo)cp.getConstant(index); 837 } 838 839 ClassFile cf = 840 new ClassFile(cp, accessFlags, thisClass, superClass, outerClass); 841 loadedClassFiles.put(cf.getClassName(), cf); 842 843 int size = din.readUnsignedShort(); 845 for (int i=0; i<size; i++) { 846 index = din.readUnsignedShort(); 847 ConstantClassInfo info = (ConstantClassInfo)cp.getConstant(index); 848 cf.addInterface(info.getClassName()); 849 } 850 851 size = din.readUnsignedShort(); 853 for (int i=0; i<size; i++) { 854 cf.mFields.add(FieldInfo.readFrom(cf, din, attrFactory)); 855 } 856 857 size = din.readUnsignedShort(); 859 for (int i=0; i<size; i++) { 860 cf.mMethods.add(MethodInfo.readFrom(cf, din, attrFactory)); 861 } 862 863 size = din.readUnsignedShort(); 865 for (int i=0; i<size; i++) { 866 Attribute attr = Attribute.readFrom(cp, din, attrFactory); 867 cf.addAttribute(attr); 868 if (attr instanceof InnerClassesAttr) { 869 cf.mInnerClassesAttr = (InnerClassesAttr)attr; 870 } 871 } 872 873 if (cf.mInnerClassesAttr != null && loader != null) { 875 InnerClassesAttr.Info[] infos = 876 cf.mInnerClassesAttr.getInnerClassesInfo(); 877 for (int i=0; i<infos.length; i++) { 878 InnerClassesAttr.Info info = infos[i]; 879 880 if (thisClass.equals(info.getInnerClass())) { 881 if (info.getInnerClassName() != null) { 883 cf.mInnerClassName = info.getInnerClassName(); 884 } 885 ConstantClassInfo outer = info.getOuterClass(); 886 if (cf.mOuterClass == null && outer != null) { 887 cf.mOuterClass = readOuterClass 888 (outer, loader, attrFactory, loadedClassFiles); 889 } 890 AccessFlags innerFlags = info.getAccessFlags(); 891 accessFlags.setStatic(innerFlags.isStatic()); 892 accessFlags.setPrivate(innerFlags.isPrivate()); 893 accessFlags.setProtected(innerFlags.isProtected()); 894 accessFlags.setPublic(innerFlags.isPublic()); 895 } 896 else if (thisClass.equals(info.getOuterClass())) { 897 ConstantClassInfo inner = info.getInnerClass(); 899 if (inner != null) { 900 ClassFile innerClass = readInnerClass 901 (inner, loader, attrFactory, loadedClassFiles, cf); 902 903 if (innerClass != null) { 904 if (innerClass.getInnerClassName() == null) { 905 innerClass.mInnerClassName = 906 info.getInnerClassName(); 907 } 908 if (cf.mInnerClasses == null) { 909 cf.mInnerClasses = new ArrayList (); 910 } 911 cf.mInnerClasses.add(innerClass); 912 } 913 } 914 } 915 } 916 } 917 918 return cf; 919 } 920 921 private static ClassFile readOuterClass(ConstantClassInfo outer, 922 ClassFileDataLoader loader, 923 AttributeFactory attrFactory, 924 Map loadedClassFiles) 925 throws IOException 926 { 927 String name = outer.getClassName(); 928 929 ClassFile outerClass = (ClassFile)loadedClassFiles.get(name); 930 if (outerClass != null) { 931 return outerClass; 932 } 933 934 InputStream in = loader.getClassData(name); 935 if (in == null) { 936 return null; 937 } 938 939 if (!(in instanceof DataInput)) { 940 in = new DataInputStream(in); 941 } 942 943 return readFrom 944 ((DataInput)in, loader, attrFactory, loadedClassFiles, null); 945 } 946 947 private static ClassFile readInnerClass(ConstantClassInfo inner, 948 ClassFileDataLoader loader, 949 AttributeFactory attrFactory, 950 Map loadedClassFiles, 951 ClassFile outerClass) 952 throws IOException 953 { 954 String name = inner.getClassName(); 955 956 ClassFile innerClass = (ClassFile)loadedClassFiles.get(name); 957 if (innerClass != null) { 958 return innerClass; 959 } 960 961 InputStream in = loader.getClassData(name); 962 if (in == null) { 963 return null; 964 } 965 966 if (!(in instanceof DataInput)) { 967 in = new DataInputStream(in); 968 } 969 970 return readFrom 971 ((DataInput)in, loader, attrFactory, loadedClassFiles, outerClass); 972 } 973 } 974 | Popular Tags |