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 }