001 package serp.bytecode;
002
003 import java.io.*;
004 import java.util.*;
005
006 import serp.bytecode.lowlevel.*;
007 import serp.bytecode.visitor.*;
008 import serp.util.*;
009
010 /**
011 * Attribute declaring the checked exceptions a method can throw.
012 *
013 * @author Abe White
014 */
015 public class Exceptions extends Attribute {
016 private List _indexes = new LinkedList();
017
018 Exceptions(int nameIndex, Attributes owner) {
019 super(nameIndex, owner);
020 }
021
022 int getLength() {
023 return 2 + (2 * _indexes.size());
024 }
025
026 /**
027 * Return the owning method.
028 */
029 public BCMethod getMethod() {
030 return (BCMethod) getOwner();
031 }
032
033 /**
034 * Return the indexes in the class {@link ConstantPool} of the
035 * {@link ClassEntry}s for the exception types thrown by this method, or
036 * an empty array if none.
037 */
038 public int[] getExceptionIndexes() {
039 int[] indexes = new int[_indexes.size()];
040 Iterator itr = _indexes.iterator();
041 for (int i = 0; i < indexes.length; i++)
042 indexes[i] = ((Integer) itr.next()).intValue();
043 return indexes;
044 }
045
046 /**
047 * Set the indexes in the class {@link ConstantPool} of the
048 * {@link ClassEntry}s for the exception types thrown by this method. Use
049 * null or an empty array for none.
050 */
051 public void setExceptionIndexes(int[] exceptionIndexes) {
052 _indexes.clear();
053 if (exceptionIndexes != null)
054 for (int i = 0; i < exceptionIndexes.length; i++)
055 _indexes.add(Numbers.valueOf(exceptionIndexes[i]));
056 }
057
058 /**
059 * Return the names of the exception types for this method, or an empty
060 * array if none. The names will be in a form suitable for a
061 * {@link Class#forName} call.
062 */
063 public String[] getExceptionNames() {
064 String[] names = new String[_indexes.size()];
065 Iterator itr = _indexes.iterator();
066 int index;
067 ClassEntry entry;
068 for (int i = 0; i < names.length; i++) {
069 index = ((Number) itr.next()).intValue();
070 entry = (ClassEntry) getPool().getEntry(index);
071 names[i] = getProject().getNameCache().getExternalForm(entry.
072 getNameEntry().getValue(), false);
073 }
074 return names;
075 }
076
077 /**
078 * Return the {@link Class} objects for the exception types for this
079 * method, or an empty array if none.
080 */
081 public Class[] getExceptionTypes() {
082 String[] names = getExceptionNames();
083 Class[] types = new Class[names.length];
084 for (int i = 0; i < names.length; i++)
085 types[i] = Strings.toClass(names[i], getClassLoader());
086 return types;
087 }
088
089 /**
090 * Return bytecode for the exception types of this
091 * method, or an empty array if none.
092 */
093 public BCClass[] getExceptionBCs() {
094 String[] names = getExceptionNames();
095 BCClass[] types = new BCClass[names.length];
096 for (int i = 0; i < names.length; i++)
097 types[i] = getProject().loadClass(names[i], getClassLoader());
098 return types;
099 }
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 }