KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > cojen > classfile > MethodInfo


1 /*
2  * Copyright 2004 Brian S O'Neill
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.cojen.classfile;
18
19 import java.util.ArrayList JavaDoc;
20 import java.util.List JavaDoc;
21 import java.io.DataInput JavaDoc;
22 import java.io.DataOutput JavaDoc;
23 import java.io.IOException JavaDoc;
24 import java.lang.reflect.Modifier JavaDoc;
25 import org.cojen.classfile.attribute.Annotation;
26 import org.cojen.classfile.attribute.AnnotationsAttr;
27 import org.cojen.classfile.attribute.CodeAttr;
28 import org.cojen.classfile.attribute.DeprecatedAttr;
29 import org.cojen.classfile.attribute.EnclosingMethodAttr;
30 import org.cojen.classfile.attribute.ExceptionsAttr;
31 import org.cojen.classfile.attribute.RuntimeInvisibleAnnotationsAttr;
32 import org.cojen.classfile.attribute.RuntimeVisibleAnnotationsAttr;
33 import org.cojen.classfile.attribute.SignatureAttr;
34 import org.cojen.classfile.attribute.SourceFileAttr;
35 import org.cojen.classfile.attribute.SyntheticAttr;
36 import org.cojen.classfile.constant.ConstantClassInfo;
37 import org.cojen.classfile.constant.ConstantUTFInfo;
38
39 /**
40  * This class corresponds to the method_info data structure as defined in
41  * section 4.6 of <i>The Java Virtual Machine Specification</i>.
42  * To make it easier to create bytecode for a method's CodeAttr, the
43  * CodeBuilder class is provided.
44  *
45  * @author Brian S O'Neill
46  * @see ClassFile
47  * @see CodeBuilder
48  */

49 public class MethodInfo {
50     private ClassFile mParent;
51     private ConstantPool mCp;
52
53     private String JavaDoc mName;
54     private MethodDesc mDesc;
55     
56     private Modifiers mModifiers;
57
58     private ConstantUTFInfo mNameConstant;
59     private ConstantUTFInfo mDescriptorConstant;
60     
61     private List JavaDoc mAttributes = new ArrayList JavaDoc(2);
62
63     private CodeAttr mCode;
64     private ExceptionsAttr mExceptions;
65
66     private int mAnonymousInnerClassCount = 0;
67
68     MethodInfo(ClassFile parent,
69                Modifiers modifiers,
70                String JavaDoc name,
71                MethodDesc desc) {
72
73         mParent = parent;
74         mCp = parent.getConstantPool();
75         mName = name;
76         mDesc = desc;
77         
78         mModifiers = modifiers;
79         mNameConstant = mCp.addConstantUTF(name);
80         mDescriptorConstant = mCp.addConstantUTF(desc.getDescriptor());
81
82         if (!modifiers.isAbstract() && !modifiers.isNative()) {
83             addAttribute(new CodeAttr(mCp));
84         }
85     }
86
87     private MethodInfo(ClassFile parent,
88                        int modifier,
89                        ConstantUTFInfo nameConstant,
90                        ConstantUTFInfo descConstant) {
91
92         mParent = parent;
93         mCp = parent.getConstantPool();
94         mName = nameConstant.getValue();
95         mDesc = MethodDesc.forDescriptor(descConstant.getValue());
96
97         mModifiers = Modifiers.getInstance(modifier);
98         mNameConstant = nameConstant;
99         mDescriptorConstant = descConstant;
100     }
101     
102     /**
103      * Returns the parent ClassFile for this MethodInfo.
104      */

105     public ClassFile getClassFile() {
106         return mParent;
107     }
108
109     /**
110      * Returns the name of this method.
111      */

112     public String JavaDoc getName() {
113         return mName;
114     }
115
116     /**
117      * Returns a MethodDesc which describes return and parameter types
118      * of this method.
119      */

120     public MethodDesc getMethodDescriptor() {
121         return mDesc;
122     }
123
124     /**
125      * Returns this method's modifiers.
126      */

127     public Modifiers getModifiers() {
128         return mModifiers;
129     }
130
131     public void setModifiers(Modifiers modifiers) {
132         mModifiers = modifiers;
133     }
134     
135     /**
136      * Returns a constant from the constant pool with this method's name.
137      */

138     public ConstantUTFInfo getNameConstant() {
139         return mNameConstant;
140     }
141     
142     /**
143      * Returns a constant from the constant pool with this method's type
144      * descriptor string.
145      * @see MethodDesc
146      */

147     public ConstantUTFInfo getDescriptorConstant() {
148         return mDescriptorConstant;
149     }
150
151     /**
152      * Returns the exceptions that this method is declared to throw.
153      */

154     public TypeDesc[] getExceptions() {
155         if (mExceptions == null) {
156             return new TypeDesc[0];
157         }
158
159         ConstantClassInfo[] classes = mExceptions.getExceptions();
160         TypeDesc[] types = new TypeDesc[classes.length];
161         for (int i=0; i<types.length; i++) {
162             types[i] = classes[i].getType();
163         }
164
165         return types;
166     }
167
168     /**
169      * Returns a CodeAttr object used to manipulate the method code body, or
170      * null if this method is abstract or native.
171      */

172     public CodeAttr getCodeAttr() {
173         return mCode;
174     }
175
176     public boolean isSynthetic() {
177         for (int i = mAttributes.size(); --i >= 0; ) {
178             Object JavaDoc obj = mAttributes.get(i);
179             if (obj instanceof SyntheticAttr) {
180                 return true;
181             }
182         }
183         return false;
184     }
185
186     public boolean isDeprecated() {
187         for (int i = mAttributes.size(); --i >= 0; ) {
188             Object JavaDoc obj = mAttributes.get(i);
189             if (obj instanceof DeprecatedAttr) {
190                 return true;
191             }
192         }
193         return false;
194     }
195
196     /**
197      * Returns all the runtime invisible annotations defined for this class
198      * file, or an empty array if none.
199      */

200     public Annotation[] getRuntimeInvisibleAnnotations() {
201         for (int i = mAttributes.size(); --i >= 0; ) {
202             Object JavaDoc obj = mAttributes.get(i);
203             if (obj instanceof RuntimeInvisibleAnnotationsAttr) {
204                 return ((AnnotationsAttr) obj).getAnnotations();
205             }
206         }
207         return new Annotation[0];
208     }
209
210     /**
211      * Returns all the runtime visible annotations defined for this class file,
212      * or an empty array if none.
213      */

214     public Annotation[] getRuntimeVisibleAnnotations() {
215         for (int i = mAttributes.size(); --i >= 0; ) {
216             Object JavaDoc obj = mAttributes.get(i);
217             if (obj instanceof RuntimeVisibleAnnotationsAttr) {
218                 return ((AnnotationsAttr) obj).getAnnotations();
219             }
220         }
221         return new Annotation[0];
222     }
223
224     /**
225      * Add a runtime invisible annotation.
226      */

227     public Annotation addRuntimeInvisibleAnnotation(TypeDesc type) {
228         AnnotationsAttr attr = null;
229         for (int i = mAttributes.size(); --i >= 0; ) {
230             Object JavaDoc obj = mAttributes.get(i);
231             if (obj instanceof RuntimeInvisibleAnnotationsAttr) {
232                 attr = (AnnotationsAttr) obj;
233             }
234         }
235         if (attr == null) {
236             attr = new RuntimeInvisibleAnnotationsAttr(mCp);
237             addAttribute(attr);
238         }
239         Annotation ann = new Annotation(mCp);
240         ann.setType(type);
241         attr.addAnnotation(ann);
242         return ann;
243     }
244
245     /**
246      * Add a runtime visible annotation.
247      */

248     public Annotation addRuntimeVisibleAnnotation(TypeDesc type) {
249         AnnotationsAttr attr = null;
250         for (int i = mAttributes.size(); --i >= 0; ) {
251             Object JavaDoc obj = mAttributes.get(i);
252             if (obj instanceof RuntimeVisibleAnnotationsAttr) {
253                 attr = (AnnotationsAttr) obj;
254             }
255         }
256         if (attr == null) {
257             attr = new RuntimeVisibleAnnotationsAttr(mCp);
258             addAttribute(attr);
259         }
260         Annotation ann = new Annotation(mCp);
261         ann.setType(type);
262         attr.addAnnotation(ann);
263         return ann;
264     }
265
266     /**
267      * Returns the signature attribute of this method, or null if none is
268      * defined.
269      */

270     // TODO: Eventually remove this method
271
public SignatureAttr getSignatureAttr() {
272         for (int i = mAttributes.size(); --i >= 0; ) {
273             Object JavaDoc obj = mAttributes.get(i);
274             if (obj instanceof SignatureAttr) {
275                 return (SignatureAttr) obj;
276             }
277         }
278         return null;
279     }
280     
281     /**
282      * Add a declared exception that this method may throw.
283      */

284     public void addException(TypeDesc type) {
285         if (mExceptions == null) {
286             addAttribute(new ExceptionsAttr(mCp));
287         }
288         // TODO: Special handling for generics
289
ConstantClassInfo cci = mCp.addConstantClass(type);
290         mExceptions.addException(cci);
291     }
292
293     /**
294      * Add an inner class to this method.
295      *
296      * @param innerClassName Optional short inner class name.
297      */

298     public ClassFile addInnerClass(String JavaDoc innerClassName) {
299         return addInnerClass(innerClassName, (String JavaDoc)null);
300     }
301
302     /**
303      * Add an inner class to this method.
304      *
305      * @param innerClassName Optional short inner class name.
306      * @param superClass Super class.
307      */

308     public ClassFile addInnerClass(String JavaDoc innerClassName, Class JavaDoc superClass) {
309         return addInnerClass(innerClassName, superClass.getName());
310     }
311
312     /**
313      * Add an inner class to this method.
314      *
315      * @param innerClassName Optional short inner class name.
316      * @param superClassName Full super class name.
317      */

318     public ClassFile addInnerClass(String JavaDoc innerClassName, String JavaDoc superClassName) {
319         ClassFile inner;
320         if (innerClassName == null) {
321             inner = mParent.addInnerClass(null, null, superClassName);
322         } else {
323             String JavaDoc fullInnerClassName = mParent.getClassName() + '$' +
324                 (++mAnonymousInnerClassCount) + innerClassName;
325             inner = mParent.addInnerClass(fullInnerClassName, innerClassName, superClassName);
326         }
327
328         if (mParent.getMajorVersion() >= 49) {
329             inner.addAttribute(new EnclosingMethodAttr
330                                (mCp, mCp.addConstantClass(mParent.getClassName()),
331                                 mCp.addConstantNameAndType(mNameConstant, mDescriptorConstant)));
332         }
333
334         return inner;
335     }
336
337     /**
338      * Mark this method as being synthetic by adding a special attribute.
339      */

340     public void markSynthetic() {
341         addAttribute(new SyntheticAttr(mCp));
342     }
343
344     /**
345      * Mark this method as being deprecated by adding a special attribute.
346      */

347     public void markDeprecated() {
348         addAttribute(new DeprecatedAttr(mCp));
349     }
350
351     public void addAttribute(Attribute attr) {
352         if (attr instanceof CodeAttr) {
353             if (mCode != null) {
354                 mAttributes.remove(mCode);
355             }
356             mCode = (CodeAttr)attr;
357         } else if (attr instanceof ExceptionsAttr) {
358             if (mExceptions != null) {
359                 mAttributes.remove(mExceptions);
360             }
361             mExceptions = (ExceptionsAttr)attr;
362         }
363
364         mAttributes.add(attr);
365     }
366
367     public Attribute[] getAttributes() {
368         Attribute[] attrs = new Attribute[mAttributes.size()];
369         return (Attribute[])mAttributes.toArray(attrs);
370     }
371
372     /**
373      * Returns the length (in bytes) of this object in the class file.
374      */

375     public int getLength() {
376         int length = 8;
377         
378         int size = mAttributes.size();
379         for (int i=0; i<size; i++) {
380             length += ((Attribute)mAttributes.get(i)).getLength();
381         }
382         
383         return length;
384     }
385     
386     public void writeTo(DataOutput JavaDoc dout) throws IOException JavaDoc {
387         dout.writeShort(mModifiers.getBitmask());
388         dout.writeShort(mNameConstant.getIndex());
389         dout.writeShort(mDescriptorConstant.getIndex());
390         
391         int size = mAttributes.size();
392         dout.writeShort(size);
393         for (int i=0; i<size; i++) {
394             Attribute attr = (Attribute)mAttributes.get(i);
395             try {
396                 attr.writeTo(dout);
397             } catch (IllegalStateException JavaDoc e) {
398                 IllegalStateException JavaDoc e2 =
399                     new IllegalStateException JavaDoc(e.getMessage() + ": " + toString());
400                 try {
401                     e2.initCause(e);
402                 } catch (NoSuchMethodError JavaDoc e3) {
403                 }
404                 throw e2;
405             }
406         }
407     }
408
409     public String JavaDoc toString() {
410         String JavaDoc str = mDesc.toMethodSignature(getName(), mModifiers.isVarArgs());
411         String JavaDoc modStr = mModifiers.toString();
412         if (modStr.length() > 0) {
413             str = modStr + ' ' + str;
414         }
415         return str;
416     }
417
418     static MethodInfo readFrom(ClassFile parent,
419                                DataInput JavaDoc din,
420                                AttributeFactory attrFactory)
421         throws IOException JavaDoc
422     {
423         ConstantPool cp = parent.getConstantPool();
424
425         int modifier = din.readUnsignedShort();
426         int index = din.readUnsignedShort();
427         ConstantUTFInfo nameConstant = (ConstantUTFInfo)cp.getConstant(index);
428         index = din.readUnsignedShort();
429         ConstantUTFInfo descConstant = (ConstantUTFInfo)cp.getConstant(index);
430
431         MethodInfo info = new MethodInfo(parent, modifier,
432                                          nameConstant, descConstant);
433
434         // Read attributes.
435
int size = din.readUnsignedShort();
436         for (int i=0; i<size; i++) {
437             info.addAttribute(Attribute.readFrom(cp, din, attrFactory));
438         }
439
440         return info;
441     }
442 }
443
Popular Tags