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 }