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 }