View Javadoc
1 package org.apache.bcel.classfile; 2 3 /* ==================================================================== 4 * The Apache Software License, Version 1.1 5 * 6 * Copyright (c) 2001 The Apache Software Foundation. All rights 7 * reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in 18 * the documentation and/or other materials provided with the 19 * distribution. 20 * 21 * 3. The end-user documentation included with the redistribution, 22 * if any, must include the following acknowledgment: 23 * "This product includes software developed by the 24 * Apache Software Foundation (http://www.apache.org/)." 25 * Alternately, this acknowledgment may appear in the software itself, 26 * if and wherever such third-party acknowledgments normally appear. 27 * 28 * 4. The names "Apache" and "Apache Software Foundation" and 29 * "Apache BCEL" must not be used to endorse or promote products 30 * derived from this software without prior written permission. For 31 * written permission, please contact apache@apache.org. 32 * 33 * 5. Products derived from this software may not be called "Apache", 34 * "Apache BCEL", nor may "Apache" appear in their name, without 35 * prior written permission of the Apache Software Foundation. 36 * 37 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 38 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 39 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 40 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 41 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 42 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 43 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 44 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 45 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 46 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 47 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 48 * SUCH DAMAGE. 49 * ==================================================================== 50 * 51 * This software consists of voluntary contributions made by many 52 * individuals on behalf of the Apache Software Foundation. For more 53 * information on the Apache Software Foundation, please see 54 * <http://www.apache.org/>;. 55 */ 56 57 import org.apache.bcel.Constants; 58 import org.apache.bcel.util.SyntheticRepository; 59 import org.apache.bcel.util.ClassVector; 60 import org.apache.bcel.util.ClassQueue; 61 import org.apache.bcel.generic.Type; 62 63 import java.io.*; 64 import java.util.StringTokenizer; 65 66 /*** 67 * Represents a Java class, i.e., the data structures, constant pool, 68 * fields, methods and commands contained in a Java .class file. 69 * See <a href="ftp://java.sun.com/docs/specs/">JVM 70 * specification</a> for details. 71 72 * The intent of this class is to represent a parsed or otherwise existing 73 * class file. Those interested in programatically generating classes 74 * should see the <a href="../generic/ClassGen.html">ClassGen</a> class. 75 76 * @version $Id: JavaClass.java,v 1.13 2002/07/11 19:39:04 mdahm Exp $ 77 * @see org.apache.bcel.generic.ClassGen 78 * @author <A HREF="mailto:markus.dahm@berlin.de">M. Dahm</A> 79 */ 80 public class JavaClass extends AccessFlags implements Cloneable, Node { 81 private String file_name; 82 private String package_name/package-summary.html">b> String package_name; 83 private String source_file_name = "<Unknown>"; 84 private int class_name_index; 85 private int superclass_name_index; 86 private String class_name; 87 private String superclass_name; 88 private int major, minor; // Compiler version 89 private ConstantPool constant_pool; // Constant pool 90 private int[] interfaces; // implemented interfaces 91 private String[] interface_names; 92 private Field[] fields; // Fields, i.e., variables of class 93 private Method[] methods; // methods defined in the class 94 private Attribute[] attributes; // attributes defined in the class 95 private byte source = HEAP; // Generated in memory 96 97 public static final byte HEAP = 1; 98 public static final byte FILE = 2; 99 public static final byte ZIP = 3; 100 101 static boolean debug = false; // Debugging on/off 102 static char sep = '/'; // directory separator 103 104 /*** 105 * In cases where we go ahead and create something, 106 * use the default SyntheticRepository, because we 107 * don't know any better. 108 */ 109 private transient org.apache.bcel.util.Repository repository = 110 SyntheticRepository.getInstance(); 111 112 /*** 113 * Constructor gets all contents as arguments. 114 * 115 * @param class_name_index Index into constant pool referencing a 116 * ConstantClass that represents this class. 117 * @param superclass_name_index Index into constant pool referencing a 118 * ConstantClass that represents this class's superclass. 119 * @param file_name File name 120 * @param major Major compiler version 121 * @param minor Minor compiler version 122 * @param access_flags Access rights defined by bit flags 123 * @param constant_pool Array of constants 124 * @param interfaces Implemented interfaces 125 * @param fields Class fields 126 * @param methods Class methods 127 * @param attributes Class attributes 128 * @param source Read from file or generated in memory? 129 */ 130 public JavaClass(int class_name_index, 131 int superclass_name_index, 132 String file_name, 133 int major, 134 int minor, 135 int access_flags, 136 ConstantPool constant_pool, 137 int[] interfaces, 138 Field[] fields, 139 Method[] methods, 140 Attribute[] attributes, 141 byte source) 142 { 143 if(interfaces == null) // Allowed for backward compatibility 144 interfaces = new int[0]; 145 if(attributes == null) 146 this.attributes = new Attribute[0]; 147 if(fields == null) 148 fields = new Field[0]; 149 if(methods == null) 150 methods = new Method[0]; 151 152 this.class_name_index = class_name_index; 153 this.superclass_name_index = superclass_name_index; 154 this.file_name = file_name; 155 this.major = major; 156 this.minor = minor; 157 this.access_flags = access_flags; 158 this.constant_pool = constant_pool; 159 this.interfaces = interfaces; 160 this.fields = fields; 161 this.methods = methods; 162 this.attributes = attributes; 163 this.source = source; 164 165 // Get source file name if available 166 for(int i=0; i < attributes.length; i++) { 167 if(attributes[i] instanceof SourceFile) { 168 source_file_name = ((SourceFile)attributes[i]).getSourceFileName(); 169 break; 170 } 171 } 172 173 /* According to the specification the following entries must be of type 174 * `ConstantClass' but we check that anyway via the 175 * `ConstPool.getConstant' method. 176 */ 177 class_name = constant_pool.getConstantString(class_name_index, 178 Constants.CONSTANT_Class); 179 class_name = Utility.compactClassName(class_name, false); 180 181 int index = class_name.lastIndexOf('.'); 182 if(index < 0) 183 package>_name = ""; 184 else 185 package>_name = class_name.substring(0, index); 186 187 if(superclass_name_index > 0) { // May be zero -> class is java.lang.Object 188 superclass_name = constant_pool.getConstantString(superclass_name_index, 189 Constants.CONSTANT_Class); 190 superclass_name = Utility.compactClassName(superclass_name, false); 191 } 192 else 193 superclass_name = "java.lang.Object"; 194 195 interface_names = new String[interfaces.length]; 196 for(int i=0; i < interfaces.length; i++) { 197 String str = constant_pool.getConstantString(interfaces[i], Constants.CONSTANT_Class); 198 interface_names[i] = Utility.compactClassName(str, false); 199 } 200 } 201 202 /*** 203 * Constructor gets all contents as arguments. 204 * 205 * @param class_name_index Class name 206 * @param superclass_name_index Superclass name 207 * @param file_name File name 208 * @param major Major compiler version 209 * @param minor Minor compiler version 210 * @param access_flags Access rights defined by bit flags 211 * @param constant_pool Array of constants 212 * @param interfaces Implemented interfaces 213 * @param fields Class fields 214 * @param methods Class methods 215 * @param attributes Class attributes 216 */ 217 public JavaClass(int class_name_index, 218 int superclass_name_index, 219 String file_name, 220 int major, 221 int minor, 222 int access_flags, 223 ConstantPool constant_pool, 224 int[] interfaces, 225 Field[] fields, 226 Method[] methods, 227 Attribute[] attributes) { 228 this(class_name_index, superclass_name_index, file_name, major, minor, access_flags, 229 constant_pool, interfaces, fields, methods, attributes, HEAP); 230 } 231 232 233 /*** 234 * Called by objects that are traversing the nodes of the tree implicitely 235 * defined by the contents of a Java class. I.e., the hierarchy of methods, 236 * fields, attributes, etc. spawns a tree of objects. 237 * 238 * @param v Visitor object 239 */ 240 public void accept(Visitor v) { 241 v.visitJavaClass(this); 242 } 243 244 /* Print debug information depending on `JavaClass.debug' 245 */ 246 static final void Debug(String str) { 247 if(debug) 248 System.out.println(str); 249 } 250 251 /*** 252 * Dump class to a file. 253 * 254 * @param file Output file 255 * @throws IOException 256 */ 257 public void dump(File file) throws IOException 258 { 259 String parent = file.getParent(); 260 261 if(parent != null) { 262 File dir = new File(parent); 263 264 if(dir != null) 265 dir.mkdirs(); 266 } 267 268 dump(new DataOutputStream(new FileOutputStream(file))); 269 } 270 271 /*** 272 * Dump class to a file named file_name. 273 * 274 * @param file_name Output file name 275 * @exception IOException 276 */ 277 public void dump(String file_name) throws IOException 278 { 279 dump(new File(file_name)); 280 } 281 282 /*** 283 * @return class in binary format 284 */ 285 public byte[] getBytes() { 286 ByteArrayOutputStream s = new ByteArrayOutputStream(); 287 DataOutputStream ds = new DataOutputStream(s); 288 289 try { 290 dump(ds); 291 } catch(IOException e) { 292 e.printStackTrace(); 293 } finally { 294 try { ds.close(); } catch(IOException e2) { e2.printStackTrace(); } 295 } 296 297 return s.toByteArray(); 298 } 299 300 /*** 301 * Dump Java class to output stream in binary format. 302 * 303 * @param file Output stream 304 * @exception IOException 305 */ 306 public void dump(OutputStream file) throws IOException { 307 dump(new DataOutputStream(file)); 308 } 309 310 /*** 311 * Dump Java class to output stream in binary format. 312 * 313 * @param file Output stream 314 * @exception IOException 315 */ 316 public void dump(DataOutputStream file) throws IOException 317 { 318 file.writeInt(0xcafebabe); 319 file.writeShort(minor); 320 file.writeShort(major); 321 322 constant_pool.dump(file); 323 324 file.writeShort(access_flags); 325 file.writeShort(class_name_index); 326 file.writeShort(superclass_name_index); 327 328 file.writeShort(interfaces.length); 329 for(int i=0; i < interfaces.length; i++) 330 file.writeShort(interfaces[i]); 331 332 file.writeShort(fields.length); 333 for(int i=0; i < fields.length; i++) 334 fields[i].dump(file); 335 336 file.writeShort(methods.length); 337 for(int i=0; i < methods.length; i++) 338 methods[i].dump(file); 339 340 if(attributes != null) { 341 file.writeShort(attributes.length); 342 for(int i=0; i < attributes.length; i++) 343 attributes[i].dump(file); 344 } 345 else 346 file.writeShort(0); 347 348 file.close(); 349 } 350 351 /*** 352 * @return Attributes of the class. 353 */ 354 public Attribute[] getAttributes() { return attributes; } 355 356 /*** 357 * @return Class name. 358 */ 359 public String getClassName() { return class_name; } 360 361 /*** 362 * @return Package name. 363 */ 364 public String getPackageName() { return package_name; } 365 366 /*** 367 * @return Class name index. 368 */ 369 public int getClassNameIndex() { return class_name_index; } 370 371 /*** 372 * @return Constant pool. 373 */ 374 public ConstantPool getConstantPool() { return constant_pool; } 375 376 /*** 377 * @return Fields, i.e., variables of the class. Like the JVM spec 378 * mandates for the classfile format, these fields are those specific to 379 * this class, and not those of the superclass or superinterfaces. 380 */ 381 public Field[] getFields() { return fields; } 382 383 /*** 384 * @return File name of class, aka SourceFile attribute value 385 */ 386 public String getFileName() { return file_name; } 387 388 /*** 389 * @return Names of implemented interfaces. 390 */ 391 public String[] getInterfaceNames() { return interface_names; } 392 393 /*** 394 * @return Indices in constant pool of implemented interfaces. 395 */ 396 public int[] getInterfaceIndices() { return interfaces; } 397 398 /*** 399 * @return Major number of class file version. 400 */ 401 public int getMajor() { return major; } 402 403 /*** 404 * @return Methods of the class. 405 */ 406 public Method[] getMethods() { return methods; } 407 408 /*** 409 * @return A org.apache.bcel.classfile.Method corresponding to 410 * java.lang.reflect.Method if any 411 */ 412 public Method getMethod(java.lang.reflect.Method m) { 413 for(int i = 0; i < methods.length; i++) { 414 Method method = methods[i]; 415 416 if(m.getName().equals(method.getName()) && 417 (m.getModifiers() == method.getModifiers()) && 418 Type.getSignature(m).equals(method.getSignature())) { 419 return method; 420 } 421 } 422 423 return null; 424 } 425 426 /*** 427 * @return Minor number of class file version. 428 */ 429 public int getMinor() { return minor; } 430 431 /*** 432 * @return sbsolute path to file where this class was read from 433 */ 434 public String getSourceFileName() { return source_file_name; } 435 436 /*** 437 * @return Superclass name. 438 */ 439 public String getSuperclassName() { return superclass_name; } 440 441 /*** 442 * @return Class name index. 443 */ 444 public int getSuperclassNameIndex() { return superclass_name_index; } 445 446 static { 447 // Debugging ... on/off 448 String debug = System.getProperty("JavaClass.debug"); 449 450 if(debug != null) 451 JavaClass.debug = new Boolean(debug).booleanValue(); 452 453 // Get path separator either / or \ usually 454 String sep = System.getProperty("file.separator"); 455 456 if(sep != null) 457 try { 458 JavaClass.sep = sep.charAt(0); 459 } catch(StringIndexOutOfBoundsException e) {} // Never reached 460 } 461 462 /*** 463 * @param attributes . 464 */ 465 public void setAttributes(Attribute[] attributes) { 466 this.attributes = attributes; 467 } 468 469 /*** 470 * @param class_name . 471 */ 472 public void setClassName(String class_name) { 473 this.class_name = class_name; 474 } 475 476 /*** 477 * @param class_name_index . 478 */ 479 public void setClassNameIndex(int class_name_index) { 480 this.class_name_index = class_name_index; 481 } 482 483 /*** 484 * @param constant_pool . 485 */ 486 public void setConstantPool(ConstantPool constant_pool) { 487 this.constant_pool = constant_pool; 488 } 489 490 /*** 491 * @param fields . 492 */ 493 public void setFields(Field[] fields) { 494 this.fields = fields; 495 } 496 497 /*** 498 * Set File name of class, aka SourceFile attribute value 499 */ 500 public void setFileName(String file_name) { 501 this.file_name = file_name; 502 } 503 504 /*** 505 * @param interface_names . 506 */ 507 public void setInterfaceNames(String[] interface_names) { 508 this.interface_names = interface_names; 509 } 510 511 /*** 512 * @param interfaces . 513 */ 514 public void setInterfaces(int[] interfaces) { 515 this.interfaces = interfaces; 516 } 517 518 /*** 519 * @param major . 520 */ 521 public void setMajor(int major) { 522 this.major = major; 523 } 524 525 /*** 526 * @param methods . 527 */ 528 public void setMethods(Method[] methods) { 529 this.methods = methods; 530 } 531 532 /*** 533 * @param minor . 534 */ 535 public void setMinor(int minor) { 536 this.minor = minor; 537 } 538 539 /*** 540 * Set absolute path to file this class was read from. 541 */ 542 public void setSourceFileName(String source_file_name) { 543 this.source_file_name = source_file_name; 544 } 545 546 /*** 547 * @param superclass_name . 548 */ 549 public void setSuperclassName(String superclass_name) { 550 this.superclass_name = superclass_name; 551 } 552 553 /*** 554 * @param superclass_name_index . 555 */ 556 public void setSuperclassNameIndex(int superclass_name_index) { 557 this.superclass_name_index = superclass_name_index; 558 } 559 560 /*** 561 * @return String representing class contents. 562 */ 563 public String toString() { 564 String access = Utility.accessToString(access_flags, true); 565 access = access.equals("")? "" : (access + " "); 566 567 StringBuffer buf = new StringBuffer(access + 568 Utility.classOrInterface(access_flags) + 569 " " + 570 class_name + " extends " + 571 Utility.compactClassName(superclass_name, 572 false) + '\n'); 573 int size = interfaces.length; 574 575 if(size > 0) { 576 buf.append("implements\t\t"); 577 578 for(int i=0; i < size; i++) { 579 buf.append(interface_names[i]); 580 if(i < size - 1) 581 buf.append(", "); 582 } 583 584 buf.append('\n'); 585 } 586 587 buf.append("filename\t\t" + file_name + '\n'); 588 buf.append("compiled from\t\t" + source_file_name + '\n'); 589 buf.append("compiler version\t" + major + "." + minor + '\n'); 590 buf.append("access flags\t\t" + access_flags + '\n'); 591 buf.append("constant pool\t\t" + constant_pool.getLength() + " entries\n"); 592 buf.append("ACC_SUPER flag\t\t" + isSuper() + "\n"); 593 594 if(attributes.length > 0) { 595 buf.append("\nAttribute(s):\n"); 596 for(int i=0; i < attributes.length; i++) 597 buf.append(indent(attributes[i])); 598 } 599 600 if(fields.length > 0) { 601 buf.append("\n" + fields.length + " fields:\n"); 602 for(int i=0; i < fields.length; i++) 603 buf.append("\t" + fields[i] + '\n'); 604 } 605 606 if(methods.length > 0) { 607 buf.append("\n" + methods.length + " methods:\n"); 608 for(int i=0; i < methods.length; i++) 609 buf.append("\t" + methods[i] + '\n'); 610 } 611 612 return buf.toString(); 613 } 614 615 private static final String indent(Object obj) { 616 StringTokenizer tok = new StringTokenizer(obj.toString(), "\n"); 617 StringBuffer buf = new StringBuffer(); 618 619 while(tok.hasMoreTokens()) 620 buf.append("\t" + tok.nextToken() + "\n"); 621 622 return buf.toString(); 623 } 624 625 /*** 626 * @return deep copy of this class 627 */ 628 public JavaClass copy() { 629 JavaClass c = null; 630 631 try { 632 c = (JavaClass)clone(); 633 } catch(CloneNotSupportedException e) {} 634 635 c.constant_pool = constant_pool.copy(); 636 c.interfaces = (int[])interfaces.clone(); 637 c.interface_names = (String[])interface_names.clone(); 638 639 c.fields = new Field[fields.length]; 640 for(int i=0; i < fields.length; i++) 641 c.fields[i] = fields[i].copy(c.constant_pool); 642 643 c.methods = new Method[methods.length]; 644 for(int i=0; i < methods.length; i++) 645 c.methods[i] = methods[i].copy(c.constant_pool); 646 647 c.attributes = new Attribute[attributes.length]; 648 for(int i=0; i < attributes.length; i++) 649 c.attributes[i] = attributes[i].copy(c.constant_pool); 650 651 return c; 652 } 653 654 public final boolean isSuper() { 655 return (access_flags & Constants.ACC_SUPER) != 0; 656 } 657 658 public final boolean isClass() { 659 return (access_flags & Constants.ACC_INTERFACE) == 0; 660 } 661 662 /*** @return returns either HEAP (generated), FILE, or ZIP 663 */ 664 public final byte getSource() { 665 return source; 666 } 667 668 /********************** New repository functionality *********************/ 669 670 /*** 671 * Gets the ClassRepository which holds its definition. By default 672 * this is the same as SyntheticRepository.getInstance(); 673 */ 674 public org.apache.bcel.util.Repository getRepository() { 675 return repository; 676 } 677 678 /*** 679 * Sets the ClassRepository which loaded the JavaClass. 680 * Should be called immediately after parsing is done. 681 */ 682 public void setRepository(org.apache.bcel.util.Repository repository) { 683 this.repository = repository; 684 } 685 686 /*** Equivalent to runtime "instanceof" operator. 687 * 688 * @return true if this JavaClass is derived from teh super class 689 */ 690 public final boolean instanceOf(JavaClass super_class) { 691 if(this.equals(super_class)) 692 return true; 693 694 JavaClass[] super_classes = getSuperClasses(); 695 696 for(int i=0; i < super_classes.length; i++) { 697 if(super_classes[i].equals(super_class)) { 698 return true; 699 } 700 } 701 702 if(super_class.isInterface()) { 703 return implementationOf(super_class); 704 } 705 706 return false; 707 } 708 709 /*** 710 * @return true, if clazz is an implementation of interface inter 711 */ 712 public boolean implementationOf(JavaClass inter) { 713 if(!inter.isInterface()) { 714 throw new IllegalArgumentException(inter.getClassName() + " is no interface"); 715 } 716 717 if(this.equals(inter)) { 718 return true; 719 } 720 721 JavaClass[] super_interfaces = getAllInterfaces(); 722 723 for(int i=0; i < super_interfaces.length; i++) { 724 if(super_interfaces[i].equals(inter)) { 725 return true; 726 } 727 } 728 729 return false; 730 } 731 732 /*** 733 * @return the superclass for this JavaClass object, or null if this 734 * is java.lang.Object 735 */ 736 public JavaClass getSuperClass() { 737 if("java.lang.Object".equals(getClassName())) { 738 return null; 739 } 740 741 try { 742 return repository.loadClass(getSuperclassName()); 743 } catch(ClassNotFoundException e) { 744 System.err.println(e); 745 return null; 746 } 747 } 748 749 /*** 750 * @return list of super classes of this class in ascending order, i.e., 751 * java.lang.Object is always the last element 752 */ 753 public JavaClass[] getSuperClasses() { 754 JavaClass clazz = this; 755 ClassVector vec = new ClassVector(); 756 757 for(clazz = clazz.getSuperClass(); clazz != null; 758 clazz = clazz.getSuperClass()) 759 { 760 vec.addElement(clazz); 761 } 762 763 return vec.toArray(); 764 } 765 766 /*** 767 * Get interfaces directly implemented by this JavaClass. 768 */ 769 public JavaClass[] getInterfaces() { 770 String[] interfaces = getInterfaceNames(); 771 JavaClass[] classes = new JavaClass[interfaces.length]; 772 773 try { 774 for(int i = 0; i < interfaces.length; i++) { 775 classes[i] = repository.loadClass(interfaces[i]); 776 } 777 } catch(ClassNotFoundException e) { 778 System.err.println(e); 779 return null; 780 } 781 782 return classes; 783 } 784 785 /*** 786 * Get all interfaces implemented by this JavaClass (transitively). 787 */ 788 public JavaClass[] getAllInterfaces() { 789 ClassQueue queue = new ClassQueue(); 790 ClassVector vec = new ClassVector(); 791 792 queue.enqueue(this); 793 794 while(!queue.empty()) { 795 JavaClass clazz = queue.dequeue(); 796 797 JavaClass souper = clazz.getSuperClass(); 798 JavaClass[] interfaces = clazz.getInterfaces(); 799 800 if(clazz.isInterface()) { 801 vec.addElement(clazz); 802 } else { 803 if(souper != null) { 804 queue.enqueue(souper); 805 } 806 } 807 808 for(int i = 0; i < interfaces.length; i++) { 809 queue.enqueue(interfaces[i]); 810 } 811 } 812 813 return vec.toArray(); 814 } 815 }

This page was automatically generated by Maven