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 privateb> 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 =/package-summary.html">>_name = "";
184 else
185 package_name = class_name/substring(0, index)/package-summary.html">>_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