KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javassist > bytecode > ClassFile


1 /*
2  * Javassist, a Java-bytecode translator toolkit.
3  * Copyright (C) 1999-2005 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  *
10  * Software distributed under the License is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12  * for the specific language governing rights and limitations under the
13  * License.
14  */

15
16 package javassist.bytecode;
17
18 import java.io.DataInputStream JavaDoc;
19 import java.io.DataOutputStream JavaDoc;
20 import java.io.IOException JavaDoc;
21 import java.util.Map JavaDoc;
22 import java.util.LinkedList JavaDoc;
23 import java.util.ArrayList JavaDoc;
24 import java.util.ListIterator JavaDoc;
25 import java.util.List JavaDoc;
26
27 import javassist.CannotCompileException;
28
29 /**
30  * <code>ClassFile</code> represents a Java <code>.class</code> file,
31  * which consists of a constant pool, methods, fields, and attributes.
32  *
33  * @see javassist.CtClass#getClassFile()
34  */

35 public final class ClassFile {
36     int major, minor; // version number
37
ConstPool constPool;
38     int thisClass;
39     int accessFlags;
40     int superClass;
41     int[] interfaces;
42     ArrayList JavaDoc fields;
43     ArrayList JavaDoc methods;
44     LinkedList JavaDoc attributes;
45
46     String JavaDoc thisclassname; // not JVM-internal name
47

48     /**
49      * Constructs a class file from a byte stream.
50      */

51     public ClassFile(DataInputStream JavaDoc in) throws IOException JavaDoc {
52         read(in);
53     }
54
55     /**
56      * Constructs a class file including no members.
57      *
58      * @param isInterface true if this is an interface.
59      * false if this is a class.
60      * @param classname a fully-qualified class name
61      * @param superclass a fully-qualified super class name
62      */

63     public ClassFile(boolean isInterface,
64                      String JavaDoc classname, String JavaDoc superclass) {
65         major = 45;
66         minor = 3; // JDK 1.1 or later
67
constPool = new ConstPool(classname);
68         thisClass = constPool.getThisClassInfo();
69         if (isInterface)
70             accessFlags = AccessFlag.SUPER | AccessFlag.INTERFACE
71                 | AccessFlag.ABSTRACT;
72         else
73             accessFlags = AccessFlag.SUPER;
74
75         initSuperclass(superclass);
76         interfaces = null;
77         fields = new ArrayList JavaDoc();
78         methods = new ArrayList JavaDoc();
79         thisclassname = classname;
80
81         attributes = new LinkedList JavaDoc();
82         attributes.add(new SourceFileAttribute(constPool,
83                                         getSourcefileName(thisclassname)));
84     }
85
86     private void initSuperclass(String JavaDoc superclass) {
87         if (superclass != null)
88             superClass = constPool.addClassInfo(superclass);
89         else
90             superClass = constPool.addClassInfo("java.lang.Object");
91     }
92
93     private static String JavaDoc getSourcefileName(String JavaDoc qname) {
94         int index = qname.lastIndexOf('.');
95         if (index >= 0)
96             qname = qname.substring(index + 1);
97
98         return qname + ".java";
99     }
100
101     /**
102      * Eliminates dead constant pool items. If a method or a field is removed,
103      * the constant pool items used by that method/field become dead items.
104      * This method recreates a constant pool.
105      */

106     public void compact() {
107         ConstPool cp = compact0();
108         ArrayList JavaDoc list = methods;
109         int n = list.size();
110         for (int i = 0; i < n; ++i) {
111             MethodInfo minfo = (MethodInfo)list.get(i);
112             minfo.compact(cp);
113         }
114
115         list = fields;
116         n = list.size();
117         for (int i = 0; i < n; ++i) {
118             FieldInfo finfo = (FieldInfo)list.get(i);
119             finfo.compact(cp);
120         }
121
122         attributes = AttributeInfo.copyAll(attributes, cp);
123         constPool = cp;
124     }
125
126     private ConstPool compact0() {
127         ConstPool cp = new ConstPool(thisclassname);
128         thisClass = cp.getThisClassInfo();
129         superClass = cp.addClassInfo(getSuperclass());
130
131         if (interfaces != null) {
132             int n = interfaces.length;
133             for (int i = 0; i < n; ++i)
134                 interfaces[i]
135                     = cp.addClassInfo(constPool.getClassInfo(interfaces[i]));
136         }
137
138         return cp;
139     }
140
141     /**
142      * Discards all attributes, associated with both the class file and
143      * the members such as a code attribute and exceptions attribute.
144      * The unused constant pool entries are also discarded (a new packed
145      * constant pool is constructed).
146      */

147     public void prune() {
148         ConstPool cp = compact0();
149
150         ArrayList JavaDoc list = methods;
151         int n = list.size();
152         for (int i = 0; i < n; ++i) {
153             MethodInfo minfo = (MethodInfo)list.get(i);
154             minfo.prune(cp);
155         }
156
157         list = fields;
158         n = list.size();
159         for (int i = 0; i < n; ++i) {
160             FieldInfo finfo = (FieldInfo)list.get(i);
161             finfo.prune(cp);
162         }
163
164         attributes = new LinkedList JavaDoc();
165         cp.prune();
166         constPool = cp;
167     }
168
169     /**
170      * Returns a constant pool table.
171      */

172     public ConstPool getConstPool() {
173         return constPool;
174     }
175
176     /**
177      * Returns true if this is an interface.
178      */

179     public boolean isInterface() {
180         return (accessFlags & AccessFlag.INTERFACE) != 0;
181     }
182
183     /**
184      * Returns true if this is a final class or interface.
185      */

186     public boolean isFinal() {
187         return (accessFlags & AccessFlag.FINAL) != 0;
188     }
189
190     /**
191      * Returns true if this is an abstract class or an interface.
192      */

193     public boolean isAbstract() {
194         return (accessFlags & AccessFlag.ABSTRACT) != 0;
195     }
196
197     /**
198      * Returns access flags.
199      *
200      * @see javassist.bytecode.AccessFlag
201      */

202     public int getAccessFlags() {
203         return accessFlags;
204     }
205
206     /**
207      * Changes access flags.
208      *
209      * @see javassist.bytecode.AccessFlag
210      */

211     public void setAccessFlags(int acc) {
212         accessFlags = acc | AccessFlag.SUPER;
213     }
214
215     /**
216      * Returns the class name.
217      */

218     public String JavaDoc getName() {
219         return thisclassname;
220     }
221
222     /**
223      * Sets the class name. This method substitutes the new name
224      * for all occurrences of the old class name in the class file.
225      */

226     public void setName(String JavaDoc name) {
227         renameClass(thisclassname, name);
228     }
229
230     /**
231      * Returns the super class name.
232      */

233     public String JavaDoc getSuperclass() {
234         return constPool.getClassInfo(superClass);
235     }
236
237     /**
238      * Returns the index of the constant pool entry representing
239      * the super class.
240      */

241     public int getSuperclassId() {
242         return superClass;
243     }
244
245     /**
246      * Sets the super class.
247      *
248      * <p>This method modifies constructors so that they call
249      * constructors declared in the new super class.
250      */

251     public void setSuperclass(String JavaDoc superclass)
252         throws CannotCompileException
253     {
254         if (superclass == null)
255             superclass = "java.lang.Object";
256
257         try {
258             superClass = constPool.addClassInfo(superclass);
259             ArrayList JavaDoc list = methods;
260             int n = list.size();
261             for (int i = 0; i < n; ++i) {
262                 MethodInfo minfo = (MethodInfo)list.get(i);
263                 minfo.setSuperclass(superclass);
264             }
265         }
266         catch (BadBytecode e) {
267             throw new CannotCompileException(e);
268         }
269     }
270
271     /**
272      * Replaces all occurrences of a class name in the class file.
273      *
274      * <p>If class X is substituted for class Y in the class file,
275      * X and Y must have the same signature. If Y provides a method
276      * m(), X must provide it even if X inherits m() from the super class.
277      * If this fact is not guaranteed, the bytecode verifier may cause
278      * an error.
279      *
280      * @param oldname the replaced class name
281      * @param newname the substituted class name
282      */

283     public final void renameClass(String JavaDoc oldname, String JavaDoc newname) {
284         ArrayList JavaDoc list;
285         int n;
286
287         if (oldname.equals(newname))
288             return;
289
290         if (oldname.equals(thisclassname))
291             thisclassname = newname;
292
293         oldname = Descriptor.toJvmName(oldname);
294         newname = Descriptor.toJvmName(newname);
295         constPool.renameClass(oldname, newname);
296
297         list = methods;
298         n = list.size();
299         for (int i = 0; i < n; ++i) {
300             MethodInfo minfo = (MethodInfo)list.get(i);
301             String JavaDoc desc = minfo.getDescriptor();
302             minfo.setDescriptor(Descriptor.rename(desc, oldname, newname));
303         }
304
305         list = fields;
306         n = list.size();
307         for (int i = 0; i < n; ++i) {
308             FieldInfo finfo = (FieldInfo)list.get(i);
309             String JavaDoc desc = finfo.getDescriptor();
310             finfo.setDescriptor(Descriptor.rename(desc, oldname, newname));
311         }
312     }
313
314     /**
315      * Replaces all occurrences of several class names in the class file.
316      *
317      * @param classnames specifies which class name is replaced
318      * with which new name. Class names must
319      * be described with the JVM-internal
320      * representation like
321      * <code>java/lang/Object</code>.
322      *
323      * @see #renameClass(String,String)
324      */

325     public final void renameClass(Map JavaDoc classnames) {
326         String JavaDoc jvmNewThisName
327             = (String JavaDoc)classnames.get(Descriptor.toJvmName(thisclassname));
328         if (jvmNewThisName != null)
329             thisclassname = Descriptor.toJavaName(jvmNewThisName);
330
331         constPool.renameClass(classnames);
332
333         ArrayList JavaDoc list = methods;
334         int n = list.size();
335         for (int i = 0; i < n; ++i) {
336             MethodInfo minfo = (MethodInfo)list.get(i);
337             String JavaDoc desc = minfo.getDescriptor();
338             minfo.setDescriptor(Descriptor.rename(desc, classnames));
339         }
340
341         list = fields;
342         n = list.size();
343         for (int i = 0; i < n; ++i) {
344             FieldInfo finfo = (FieldInfo)list.get(i);
345             String JavaDoc desc = finfo.getDescriptor();
346             finfo.setDescriptor(Descriptor.rename(desc, classnames));
347         }
348     }
349
350     /**
351      * Returns the names of the interfaces implemented by the class.
352      */

353     public String JavaDoc[] getInterfaces() {
354         if (interfaces == null)
355             return new String JavaDoc[0];
356         else {
357             int n = interfaces.length;
358             String JavaDoc[] list = new String JavaDoc[n];
359             for (int i = 0; i < n; ++i)
360                 list[i] = constPool.getClassInfo(interfaces[i]);
361
362             return list;
363         }
364     }
365
366     /**
367      * Sets the interfaces.
368      *
369      * @param nameList the names of the interfaces.
370      */

371     public void setInterfaces(String JavaDoc[] nameList) {
372         if (nameList != null) {
373             int n = nameList.length;
374             interfaces = new int[n];
375             for (int i = 0; i < n; ++i)
376                 interfaces[i] = constPool.addClassInfo(nameList[i]);
377         }
378     }
379
380     /**
381      * Appends an interface to the
382      * interfaces implemented by the class.
383      */

384     public void addInterface(String JavaDoc name) {
385         int info = constPool.addClassInfo(name);
386         if (interfaces == null) {
387             interfaces = new int[1];
388             interfaces[0] = info;
389         }
390         else {
391             int n = interfaces.length;
392             int[] newarray = new int[n + 1];
393             System.arraycopy(interfaces, 0, newarray, 0, n);
394             newarray[n] = info;
395             interfaces = newarray;
396         }
397     }
398
399     /**
400      * Returns all the fields declared in the class.
401      *
402      * @return a list of <code>FieldInfo</code>.
403      * @see FieldInfo
404      */

405     public List JavaDoc getFields() {
406         return fields;
407     }
408
409     /**
410      * Appends a field to the class.
411      */

412     public void addField(FieldInfo finfo) throws CannotCompileException {
413         testExistingField(finfo.getName(), finfo.getDescriptor());
414         fields.add(finfo);
415     }
416
417     private void addField0(FieldInfo finfo) {
418         fields.add(finfo);
419     }
420
421     private void testExistingField(String JavaDoc name, String JavaDoc descriptor)
422         throws CannotCompileException
423     {
424         ListIterator JavaDoc it = fields.listIterator(0);
425         while (it.hasNext()) {
426             FieldInfo minfo = (FieldInfo)it.next();
427             if (minfo.getName().equals(name))
428                 throw new CannotCompileException("duplicate field: " + name);
429         }
430     }
431
432     /**
433      * Returns all the methods declared in the class.
434      *
435      * @return a list of <code>MethodInfo</code>.
436      * @see MethodInfo
437      */

438     public List JavaDoc getMethods() {
439         return methods;
440     }
441
442     /**
443      * Returns the method with the specified name. If there are multiple
444      * methods with that name, this method returns one of them.
445      *
446      * @return null if no such a method is found.
447      */

448     public MethodInfo getMethod(String JavaDoc name) {
449         ArrayList JavaDoc list = methods;
450         int n = list.size();
451         for (int i = 0; i < n; ++i) {
452             MethodInfo minfo = (MethodInfo)list.get(i);
453             if (minfo.getName().equals(name))
454                 return minfo;
455         }
456
457         return null;
458     }
459
460     /**
461      * Returns a static initializer (class initializer), or null if
462      * it does not exist.
463      */

464     public MethodInfo getStaticInitializer() {
465         return getMethod(MethodInfo.nameClinit);
466     }
467
468     /**
469      * Appends a method to the class.
470      */

471     public void addMethod(MethodInfo minfo) throws CannotCompileException {
472         testExistingMethod(minfo.getName(), minfo.getDescriptor());
473         methods.add(minfo);
474     }
475
476     private void addMethod0(MethodInfo minfo) {
477         methods.add(minfo);
478     }
479
480     private void testExistingMethod(String JavaDoc name, String JavaDoc descriptor)
481         throws CannotCompileException
482     {
483         ListIterator JavaDoc it = methods.listIterator(0);
484         while (it.hasNext()) {
485             MethodInfo minfo = (MethodInfo)it.next();
486             if (minfo.getName().equals(name)
487                 && Descriptor.eqParamTypes(minfo.getDescriptor(), descriptor))
488                 throw new CannotCompileException("duplicate method: " + name);
489         }
490     }
491
492     /**
493      * Returns all the attributes.
494      *
495      * @return a list of <code>AttributeInfo</code> objects.
496      * @see AttributeInfo
497      */

498     public List JavaDoc getAttributes() {
499         return attributes;
500     }
501
502     /**
503      * Returns the attribute with the specified name.
504      *
505      * @param name attribute name
506      */

507     public AttributeInfo getAttribute(String JavaDoc name) {
508         LinkedList JavaDoc list = attributes;
509         int n = list.size();
510         for (int i = 0; i < n; ++i) {
511             AttributeInfo ai = (AttributeInfo)list.get(i);
512             if (ai.getName().equals(name))
513                 return ai;
514         }
515
516         return null;
517     }
518
519     /**
520      * Appends an attribute. If there is already an attribute with
521      * the same name, the new one substitutes for it.
522      */

523     public void addAttribute(AttributeInfo info) {
524         AttributeInfo.remove(attributes, info.getName());
525         attributes.add(info);
526     }
527
528     /**
529      * Returns the source file containing this class.
530      *
531      * @return null if this information is not available.
532      */

533     public String JavaDoc getSourceFile() {
534         SourceFileAttribute sf
535             = (SourceFileAttribute)getAttribute(SourceFileAttribute.tag);
536         if (sf == null)
537             return null;
538         else
539             return sf.getFileName();
540     }
541
542     private void read(DataInputStream JavaDoc in) throws IOException JavaDoc {
543         int i, n;
544         int magic = in.readInt();
545         if (magic != 0xCAFEBABE)
546             throw new IOException JavaDoc("non class file");
547
548         minor = in.readUnsignedShort();
549         major = in.readUnsignedShort();
550         constPool = new ConstPool(in);
551         accessFlags = in.readUnsignedShort();
552         thisClass = in.readUnsignedShort();
553         constPool.setThisClassInfo(thisClass);
554         superClass = in.readUnsignedShort();
555         n = in.readUnsignedShort();
556         if (n == 0)
557             interfaces = null;
558         else {
559             interfaces = new int[n];
560             for (i = 0; i < n; ++i)
561                 interfaces[i] = in.readUnsignedShort();
562         }
563
564         ConstPool cp = constPool;
565         n = in.readUnsignedShort();
566         fields = new ArrayList JavaDoc();
567         for (i = 0; i < n; ++i)
568             addField0(new FieldInfo(cp, in));
569
570         n = in.readUnsignedShort();
571         methods = new ArrayList JavaDoc();
572         for (i = 0; i < n; ++i)
573             addMethod0(new MethodInfo(cp, in));
574
575         attributes = new LinkedList JavaDoc();
576         n = in.readUnsignedShort();
577         for (i = 0; i < n; ++i)
578             addAttribute(AttributeInfo.read(cp, in));
579
580         thisclassname = constPool.getClassInfo(thisClass);
581     }
582
583     /**
584      * Writes a class file represened by this object
585      * into an output stream.
586      */

587     public void write(DataOutputStream JavaDoc out) throws IOException JavaDoc {
588         int i, n;
589
590         out.writeInt(0xCAFEBABE); // magic
591
out.writeShort(minor); // minor version
592
out.writeShort(major); // major version
593
constPool.write(out); // constant pool
594
out.writeShort(accessFlags);
595         out.writeShort(thisClass);
596         out.writeShort(superClass);
597
598         if (interfaces == null)
599             n = 0;
600         else
601             n = interfaces.length;
602
603         out.writeShort(n);
604         for (i = 0; i < n; ++i)
605             out.writeShort(interfaces[i]);
606
607         ArrayList JavaDoc list = fields;
608         n = list.size();
609         out.writeShort(n);
610         for (i = 0; i < n; ++i) {
611             FieldInfo finfo = (FieldInfo)list.get(i);
612             finfo.write(out);
613         }
614
615         list = methods;
616         n = list.size();
617         out.writeShort(n);
618         for (i = 0; i < n; ++i) {
619             MethodInfo minfo = (MethodInfo)list.get(i);
620             minfo.write(out);
621         }
622
623         out.writeShort(attributes.size());
624         AttributeInfo.writeAll(attributes, out);
625     }
626 }
627
Popular Tags