View Javadoc

1   package serp.bytecode;
2   
3   import java.io.*;
4   import java.util.*;
5   
6   import serp.bytecode.lowlevel.*;
7   import serp.bytecode.visitor.*;
8   import serp.util.*;
9   
10  /***
11   * Attribute declaring the checked exceptions a method can throw.
12   *
13   * @author Abe White
14   */
15  public class Exceptions extends Attribute {
16      private List _indexes = new LinkedList();
17  
18      Exceptions(int nameIndex, Attributes owner) {
19          super(nameIndex, owner);
20      }
21  
22      int getLength() {
23          return 2 + (2 * _indexes.size());
24      }
25  
26      /***
27       * Return the owning method.
28       */
29      public BCMethod getMethod() {
30          return (BCMethod) getOwner();
31      }
32  
33      /***
34       * Return the indexes in the class {@link ConstantPool} of the
35       * {@link ClassEntry}s for the exception types thrown by this method, or
36       * an empty array if none.
37       */
38      public int[] getExceptionIndexes() {
39          int[] indexes = new int[_indexes.size()];
40          Iterator itr = _indexes.iterator();
41          for (int i = 0; i < indexes.length; i++)
42              indexes[i] = ((Integer) itr.next()).intValue();
43          return indexes;
44      }
45  
46      /***
47       * Set the indexes in the class {@link ConstantPool} of the
48       * {@link ClassEntry}s for the exception types thrown by this method. Use
49       * null or an empty array for none.
50       */
51      public void setExceptionIndexes(int[] exceptionIndexes) {
52          _indexes.clear();
53          if (exceptionIndexes != null)
54              for (int i = 0; i < exceptionIndexes.length; i++)
55                  _indexes.add(Numbers.valueOf(exceptionIndexes[i]));
56      }
57  
58      /***
59       * Return the names of the exception types for this method, or an empty
60       * array if none. The names will be in a form suitable for a
61       * {@link Class#forName} call.
62       */
63      public String[] getExceptionNames() {
64          String[] names = new String[_indexes.size()];
65          Iterator itr = _indexes.iterator();
66          int index;
67          ClassEntry entry;
68          for (int i = 0; i < names.length; i++) {
69              index = ((Number) itr.next()).intValue();
70              entry = (ClassEntry) getPool().getEntry(index);
71              names[i] = getProject().getNameCache().getExternalForm(entry.
72                  getNameEntry().getValue(), false);
73          }
74          return names;
75      }
76  
77      /***
78       * Return the {@link Class} objects for the exception types for this
79       * method, or an empty array if none.
80       */
81      public Class[] getExceptionTypes() {
82          String[] names = getExceptionNames();
83          Class[] types = new Class[names.length];
84          for (int i = 0; i < names.length; i++)
85              types[i] = Strings.toClass(names[i], getClassLoader());
86          return types;
87      }
88  
89      /***
90       * Return bytecode for the exception types of this
91       * method, or an empty array if none.
92       */
93      public BCClass[] getExceptionBCs() {
94          String[] names = getExceptionNames();
95          BCClass[] types = new BCClass[names.length];
96          for (int i = 0; i < names.length; i++)
97              types[i] = getProject().loadClass(names[i], getClassLoader());
98          return types;
99      }
100 
101     /***
102      * Set the checked exceptions thrown by this method. Use null or an
103      * empty array for none.
104      */
105     public void setExceptions(String[] exceptions) {
106         if (exceptions != null) {
107             for (int i = 0; i < exceptions.length; i++)
108                 if (exceptions[i] == null)
109                     throw new NullPointerException("exceptions[" + i 
110                         + "] = null");
111         }
112 
113         clear();
114         if (exceptions != null)
115             for (int i = 0; i < exceptions.length; i++)
116                 addException(exceptions[i]);
117     }
118 
119     /***
120      * Set the checked exceptions thrown by this method. Use null or an
121      * empty array for none.
122      */
123     public void setExceptions(Class[] exceptions) {
124         String[] names = null;
125         if (exceptions != null) {
126             names = new String[exceptions.length];
127             for (int i = 0; i < exceptions.length; i++)
128                 names[i] = exceptions[i].getName();
129         }
130         setExceptions(names);
131     }
132 
133     /***
134      * Set the checked exceptions thrown by this method. Use null or an
135      * empty array for none.
136      */
137     public void setExceptions(BCClass[] exceptions) {
138         String[] names = null;
139         if (exceptions != null) {
140             names = new String[exceptions.length];
141             for (int i = 0; i < exceptions.length; i++)
142                 names[i] = exceptions[i].getName();
143         }
144         setExceptions(names);
145     }
146 
147     /***
148      * Clear this method of all exception declarations.
149      */
150     public void clear() {
151         _indexes.clear();
152     }
153 
154     /***
155      * Remove an exception type thrown by this method.
156      *
157      * @return true if the method had the exception type, false otherwise
158      */
159     public boolean removeException(String type) {
160         String internalForm = getProject().getNameCache().getInternalForm(type,
161             false);
162         ClassEntry entry;
163         for (Iterator itr = _indexes.iterator(); itr.hasNext();) {
164             entry = (ClassEntry) getPool().getEntry(((Integer) itr.next()).
165                 intValue());
166             if (entry.getNameEntry().getValue().equals(internalForm)) {
167                 itr.remove();
168                 return true;
169             }
170         }
171         return false;
172     }
173 
174     /***
175      * Remove an exception thrown by this method.
176      *
177      * @return true if the method had the exception type, false otherwise
178      */
179     public boolean removeException(Class type) {
180         if (type == null)
181             return false;
182         return removeException(type.getName());
183     }
184 
185     /***
186      * Remove an exception thrown by this method.
187      *
188      * @return true if the method had the exception type, false otherwise
189      */
190     public boolean removeException(BCClass type) {
191         if (type == null)
192             return false;
193         return removeException(type.getName());
194     }
195 
196     /***
197      * Add an exception type to those thrown by this method.
198      */
199     public void addException(String type) {
200         int index = getPool().findClassEntry(getProject().getNameCache().
201             getInternalForm(type, false), true);
202         _indexes.add(Numbers.valueOf(index));
203     }
204 
205     /***
206      * Add an exception to those thrown by this method.
207      */
208     public void addException(Class type) {
209         addException(type.getName());
210     }
211 
212     /***
213      * Add an exception to those thrown by this method.
214      */
215     public void addException(BCClass type) {
216         addException(type.getName());
217     }
218 
219     /***
220      * Return true if the method declares that it throws the given
221      * exception type.
222      */
223     public boolean throwsException(String type) {
224         String[] exceptions = getExceptionNames();
225         for (int i = 0; i < exceptions.length; i++)
226             if (exceptions[i].equals(type))
227                 return true;
228         return false;
229     }
230 
231     /***
232      * Return true if the method declares that it throws the given
233      * exception type.
234      */
235     public boolean throwsException(Class type) {
236         if (type == null)
237             return false;
238         return throwsException(type.getName());
239     }
240 
241     /***
242      * Return true if the method declares that it throws the given
243      * exception type.
244      */
245     public boolean throwsException(BCClass type) {
246         if (type == null)
247             return false;
248         return throwsException(type.getName());
249     }
250 
251     public void acceptVisit(BCVisitor visit) {
252         visit.enterExceptions(this);
253         visit.exitExceptions(this);
254     }
255 
256     void read(Attribute other) {
257         setExceptions(((Exceptions) other).getExceptionNames());
258     }
259 
260     void read(DataInput in, int length) throws IOException {
261         _indexes.clear();
262         int exceptionCount = in.readUnsignedShort();
263         for (int i = 0; i < exceptionCount; i++)
264             _indexes.add(Numbers.valueOf((int) in.readUnsignedShort()));
265     }
266 
267     void write(DataOutput out, int length) throws IOException {
268         out.writeShort(_indexes.size());
269         for (Iterator itr = _indexes.iterator(); itr.hasNext();)
270             out.writeShort(((Number) itr.next()).shortValue());
271     }
272 }