1/* 2 * Javassist, a Java-bytecode translator toolkit. 3 * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved. 4 * 5 * The contents of this file are subject to the Mozilla Public License Version 6 * 1.1 (the "License"); you may not use this file except in compliance with 7 * the License. Alternatively, the contents of this file may be used under 8 * the terms of the GNU Lesser General Public License Version 2.1 or later. 9 * 10 * Software distributed under the License is distributed on an "AS IS" basis, 11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 12 * for the specific language governing rights and limitations under the 13 * License. 14 */ 15 16package javassist.bytecode.annotation; 17 18import java.io.*; 19 20import javassist.bytecode.ByteArray; 21import javassist.bytecode.ConstPool; 22 23/** 24 * A convenience class for constructing a 25 * <code>..Annotations_attribute</code>. 26 * See the source code of the <code>AnnotationsAttribute.Copier</code> class. 27 * 28 * <p>The following code snippet is an example of use of this class: 29 * 30 * <ul><pre> 31 * ConstPool pool = ...; 32 * output = new ByteArrayOutputStream(); 33 * writer = new AnnotationsWriter(output, pool); 34 * 35 * writer.numAnnotations(1); 36 * writer.annotation("Author", 2); 37 * writer.memberValuePair("name"); 38 * writer.constValueIndex("chiba"); 39 * writer.memberValuePair("address"); 40 * writer.constValueIndex("tokyo"); 41 * 42 * writer.close(); 43 * byte[] attribute_info = output.toByteArray(); 44 * AnnotationsAttribute anno 45 * = new AnnotationsAttribute(pool, AnnotationsAttribute.visibleTag, 46 * attribute_info); 47 * </pre></ul> 48 * 49 * <p>The code snippet above generates the annotation attribute 50 * corresponding to this annotation: 51 * 52 * <ul><pre> 53 * @Author(name = "chiba", address = "tokyo") 54 * </pre></ul> 55 * 56 * @see javassist.bytecode.AnnotationsAttribute 57 * @see javassist.bytecode.ParameterAnnotationsAttribute 58 */ 59public class AnnotationsWriter { 60 private OutputStream output; 61 private ConstPool pool; 62 63 /** 64 * Constructs with the given output stream. 65 * 66 * @param os the output stream. 67 * @param cp the constant pool. 68 */ 69 public AnnotationsWriter(OutputStream os, ConstPool cp) { 70 output = os; 71 pool = cp; 72 } 73 74 /** 75 * Obtains the constant pool given to the constructor. 76 */ 77 public ConstPool getConstPool() { 78 return pool; 79 } 80 81 /** 82 * Closes the output stream. 83 * 84 */ 85 public void close() throws IOException { 86 output.close(); 87 } 88 89 /** 90 * Writes <code>num_parameters</code> in 91 * <code>Runtime(In)VisibleParameterAnnotations_attribute</code>. 92 * This method must be followed by <code>num</code> calls to 93 * <code>numAnnotations()</code>. 94 */ 95 public void numParameters(int num) throws IOException { 96 output.write(num); 97 } 98 99 /** 100 * Writes <code>num_annotations</code> in 101 * <code>Runtime(In)VisibleAnnotations_attribute</code>. 102 * This method must be followed by <code>num</code> calls to 103 * <code>annotation()</code>. 104 */ 105 public void numAnnotations(int num) throws IOException { 106 write16bit(num); 107 } 108 109 /** 110 * Writes <code>annotation</code>. 111 * This method must be followed by <code>numMemberValuePairs</code> 112 * calls to <code>memberValuePair()</code>. 113 * 114 * @param type the annotation interface name. 115 * @param numMemberValuePairs <code>num_member_value_pairs</code> 116 * in <code>annotation</code>. 117 */ 118 public void annotation(String type, int numMemberValuePairs) 119 throws IOException 120 { 121 annotation(pool.addUtf8Info(type), numMemberValuePairs); 122 } 123 124 /** 125 * Writes <code>annotation</code>. 126 * This method must be followed by <code>numMemberValuePairs</code> 127 * calls to <code>memberValuePair()</code>. 128 * 129 * @param typeIndex <code>type_index</code> in <code>annotation</code>. 130 * @param numMemberValuePairs <code>num_member_value_pairs</code> 131 * in <code>annotation</code>. 132 */ 133 public void annotation(int typeIndex, int numMemberValuePairs) 134 throws IOException 135 { 136 write16bit(typeIndex); 137 write16bit(numMemberValuePairs); 138 } 139 140 /** 141 * Writes an element of a <code>member_value_pairs</code> array 142 * in <code>annotation</code>. 143 * This method must be followed by a 144 * call to <code>constValueIndex()</code>, <code>enumConstValue()</code>, 145 * etc. 146 * 147 * @param memberName the name of the annotation type member. 148 */ 149 public void memberValuePair(String memberName) throws IOException { 150 memberValuePair(pool.addUtf8Info(memberName)); 151 } 152 153 /** 154 * Writes an element of a <code>member_value_pairs</code> array 155 * in <code>annotation</code>. 156 * This method must be followed by a 157 * call to <code>constValueIndex()</code>, <code>enumConstValue()</code>, 158 * etc. 159 * 160 * @param memberNameIndex <code>member_name_index</code> 161 * in <code>member_value_pairs</code> array. 162 */ 163 public void memberValuePair(int memberNameIndex) throws IOException { 164 write16bit(memberNameIndex); 165 } 166 167 /** 168 * Writes <code>tag</code> and <code>const_value_index</code> 169 * in <code>member_value</code>. 170 * 171 * @param value the constant value. 172 */ 173 public void constValueIndex(boolean value) throws IOException { 174 constValueIndex('Z', pool.addIntegerInfo(value ? 1 : 0)); 175 } 176 177 /** 178 * Writes <code>tag</code> and <code>const_value_index</code> 179 * in <code>member_value</code>. 180 * 181 * @param value the constant value. 182 */ 183 public void constValueIndex(byte value) throws IOException { 184 constValueIndex('B', pool.addIntegerInfo(value)); 185 } 186 187 /** 188 * Writes <code>tag</code> and <code>const_value_index</code> 189 * in <code>member_value</code>. 190 * 191 * @param value the constant value. 192 */ 193 public void constValueIndex(char value) throws IOException { 194 constValueIndex('C', pool.addIntegerInfo(value)); 195 } 196 197 /** 198 * Writes <code>tag</code> and <code>const_value_index</code> 199 * in <code>member_value</code>. 200 * 201 * @param value the constant value. 202 */ 203 public void constValueIndex(short value) throws IOException { 204 constValueIndex('S', pool.addIntegerInfo(value)); 205 } 206 207 /** 208 * Writes <code>tag</code> and <code>const_value_index</code> 209 * in <code>member_value</code>. 210 * 211 * @param value the constant value. 212 */ 213 public void constValueIndex(int value) throws IOException { 214 constValueIndex('I', pool.addIntegerInfo(value)); 215 } 216 217 /** 218 * Writes <code>tag</code> and <code>const_value_index</code> 219 * in <code>member_value</code>. 220 * 221 * @param value the constant value. 222 */ 223 public void constValueIndex(long value) throws IOException { 224 constValueIndex('J', pool.addLongInfo(value)); 225 } 226 227 /** 228 * Writes <code>tag</code> and <code>const_value_index</code> 229 * in <code>member_value</code>. 230 * 231 * @param value the constant value. 232 */ 233 public void constValueIndex(float value) throws IOException { 234 constValueIndex('F', pool.addFloatInfo(value)); 235 } 236 237 /** 238 * Writes <code>tag</code> and <code>const_value_index</code> 239 * in <code>member_value</code>. 240 * 241 * @param value the constant value. 242 */ 243 public void constValueIndex(double value) throws IOException { 244 constValueIndex('D', pool.addDoubleInfo(value)); 245 } 246 247 /** 248 * Writes <code>tag</code> and <code>const_value_index</code> 249 * in <code>member_value</code>. 250 * 251 * @param value the constant value. 252 */ 253 public void constValueIndex(String value) throws IOException { 254 constValueIndex('s', pool.addUtf8Info(value)); 255 } 256 257 /** 258 * Writes <code>tag</code> and <code>const_value_index</code> 259 * in <code>member_value</code>. 260 * 261 * @param tag <code>tag</code> in <code>member_value</code>. 262 * @param index <code>const_value_index</code> 263 * in <code>member_value</code>. 264 */ 265 public void constValueIndex(int tag, int index) 266 throws IOException 267 { 268 output.write(tag); 269 write16bit(index); 270 } 271 272 /** 273 * Writes <code>tag</code> and <code>enum_const_value</code> 274 * in <code>member_value</code>. 275 * 276 * @param typeName the type name of the enum constant. 277 * @param constName the simple name of the enum constant. 278 */ 279 public void enumConstValue(String typeName, String constName) 280 throws IOException 281 { 282 enumConstValue(pool.addUtf8Info(typeName), 283 pool.addUtf8Info(constName)); 284 } 285 286 /** 287 * Writes <code>tag</code> and <code>enum_const_value</code> 288 * in <code>member_value</code>. 289 * 290 * @param typeNameIndex <code>type_name_index</code> 291 * in <code>member_value</code>. 292 * @param constNameIndex <code>const_name_index</code> 293 * in <code>member_value</code>. 294 */ 295 public void enumConstValue(int typeNameIndex, int constNameIndex) 296 throws IOException 297 { 298 output.write('e'); 299 write16bit(typeNameIndex); 300 write16bit(constNameIndex); 301 } 302 303 /** 304 * Writes <code>tag</code> and <code>class_info_index</code> 305 * in <code>member_value</code>. 306 * 307 * @param name the class name. 308 */ 309 public void classInfoIndex(String name) throws IOException { 310 classInfoIndex(pool.addUtf8Info(name)); 311 } 312 313 /** 314 * Writes <code>tag</code> and <code>class_info_index</code> 315 * in <code>member_value</code>. 316 * 317 * @param index <code>class_info_index</code> 318 */ 319 public void classInfoIndex(int index) throws IOException { 320 output.write('c'); 321 write16bit(index); 322 } 323 324 /** 325 * Writes <code>tag</code> and <code>annotation_value</code> 326 * in <code>member_value</code>. 327 * This method must be followed by a call to <code>annotation()</code>. 328 */ 329 public void annotationValue() throws IOException { 330 output.write('@'); 331 } 332 333 /** 334 * Writes <code>tag</code> and <code>array_value</code> 335 * in <code>member_value</code>. 336 * This method must be followed by <code>numValues</code> calls 337 * to <code>constValueIndex()</code>, <code>enumConstValue()</code>, 338 * etc. 339 * 340 * @param numValues <code>num_values</code> 341 * in <code>array_value</code>. 342 */ 343 public void arrayValue(int numValues) throws IOException { 344 output.write('['); 345 write16bit(numValues); 346 } 347 348 private void write16bit(int value) throws IOException { 349 byte[] buf = new byte[2]; 350 ByteArray.write16bit(value, buf, 0); 351 output.write(buf); 352 } 353} 354