1 /* 2 * Javassist, a Java-bytecode translator toolkit. 3 * Copyright (C) 1999- 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 * or the Apache License Version 2.0. 10 * 11 * Software distributed under the License is distributed on an "AS IS" basis, 12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 13 * for the specific language governing rights and limitations under the 14 * License. 15 */ 16 17 package javassist.bytecode; 18 19 import java.io.ByteArrayOutputStream; 20 import java.io.DataInputStream; 21 import java.io.IOException; 22 import java.util.HashMap; 23 import java.util.Map; 24 25 import javassist.bytecode.annotation.Annotation; 26 import javassist.bytecode.annotation.AnnotationMemberValue; 27 import javassist.bytecode.annotation.AnnotationsWriter; 28 import javassist.bytecode.annotation.ArrayMemberValue; 29 import javassist.bytecode.annotation.BooleanMemberValue; 30 import javassist.bytecode.annotation.ByteMemberValue; 31 import javassist.bytecode.annotation.CharMemberValue; 32 import javassist.bytecode.annotation.ClassMemberValue; 33 import javassist.bytecode.annotation.DoubleMemberValue; 34 import javassist.bytecode.annotation.EnumMemberValue; 35 import javassist.bytecode.annotation.FloatMemberValue; 36 import javassist.bytecode.annotation.IntegerMemberValue; 37 import javassist.bytecode.annotation.LongMemberValue; 38 import javassist.bytecode.annotation.MemberValue; 39 import javassist.bytecode.annotation.ShortMemberValue; 40 import javassist.bytecode.annotation.StringMemberValue; 41 42 /** 43 * A class representing 44 * <code>RuntimeVisibleAnnotations_attribute</code> and 45 * <code>RuntimeInvisibleAnnotations_attribute</code>. 46 * 47 * <p>To obtain an AnnotationAttribute object, invoke 48 * <code>getAttribute(AnnotationsAttribute.visibleTag)</code> 49 * in <code>ClassFile</code>, <code>MethodInfo</code>, 50 * or <code>FieldInfo</code>. The obtained attribute is a 51 * runtime visible annotations attribute. 52 * If the parameter is 53 * <code>AnnotationAttribute.invisibleTag</code>, then the obtained 54 * attribute is a runtime invisible one. 55 * 56 * <p>For example, 57 * 58 * <pre> 59 * import javassist.bytecode.annotation.Annotation; 60 * : 61 * CtMethod m = ... ; 62 * MethodInfo minfo = m.getMethodInfo(); 63 * AnnotationsAttribute attr = (AnnotationsAttribute) 64 * minfo.getAttribute(AnnotationsAttribute.invisibleTag); 65 * Annotation an = attr.getAnnotation("Author"); 66 * String s = ((StringMemberValue)an.getMemberValue("name")).getValue(); 67 * System.out.println("@Author(name=" + s + ")"); 68 * </pre> 69 * 70 * <p>This code snippet retrieves an annotation of the type <code>Author</code> 71 * from the <code>MethodInfo</code> object specified by <code>minfo</code>. 72 * Then, it prints the value of <code>name</code> in <code>Author</code>. 73 * 74 * <p>If the annotation type <code>Author</code> is annotated by a meta annotation: 75 * 76 * <pre> 77 * @Retention(RetentionPolicy.RUNTIME) 78 * </pre> 79 * 80 * <p>Then <code>Author</code> is visible at runtime. Therefore, the third 81 * statement of the code snippet above must be changed into: 82 * 83 * <pre> 84 * AnnotationsAttribute attr = (AnnotationsAttribute) 85 * minfo.getAttribute(AnnotationsAttribute.visibleTag); 86 * </pre> 87 * 88 * <p>The attribute tag must be <code>visibleTag</code> instead of 89 * <code>invisibleTag</code>. 90 * 91 * <p>If the member value of an annotation is not specified, the default value 92 * is used as that member value. If so, <code>getMemberValue()</code> in 93 * <code>Annotation</code> returns <code>null</code> 94 * since the default value is not included in the 95 * <code>AnnotationsAttribute</code>. It is included in the 96 * <code>AnnotationDefaultAttribute</code> of the method declared in the 97 * annotation type. 98 * 99 * <p>If you want to record a new AnnotationAttribute object, execute the 100 * following snippet: 101 * 102 * <pre> 103 * ClassFile cf = ... ; 104 * ConstPool cp = cf.getConstPool(); 105 * AnnotationsAttribute attr 106 * = new AnnotationsAttribute(cp, AnnotationsAttribute.visibleTag); 107 * Annotation a = new Annotation("Author", cp); 108 * a.addMemberValue("name", new StringMemberValue("Chiba", cp)); 109 * attr.setAnnotation(a); 110 * cf.addAttribute(attr); 111 * cf.setVersionToJava5(); 112 * </pre> 113 * 114 * <p>The last statement is necessary if the class file was produced by 115 * <code>javac</code> of JDK 1.4 or earlier. Otherwise, it is not necessary. 116 * 117 * @see AnnotationDefaultAttribute 118 * @see javassist.bytecode.annotation.Annotation 119 */ 120 public class AnnotationsAttribute extends AttributeInfo { 121 /** 122 * The name of the <code>RuntimeVisibleAnnotations</code> attribute. 123 */ 124 public static final String visibleTag = "RuntimeVisibleAnnotations"; 125 126 /** 127 * The name of the <code>RuntimeInvisibleAnnotations</code> attribute. 128 */ 129 public static final String invisibleTag = "RuntimeInvisibleAnnotations"; 130 131 /** 132 * Constructs a <code>Runtime(In)VisibleAnnotations_attribute</code>. 133 * 134 * @param cp constant pool 135 * @param attrname attribute name (<code>visibleTag</code> or 136 * <code>invisibleTag</code>). 137 * @param info the contents of this attribute. It does not 138 * include <code>attribute_name_index</code> or 139 * <code>attribute_length</code>. 140 */ AnnotationsAttribute(ConstPool cp, String attrname, byte[] info)141 public AnnotationsAttribute(ConstPool cp, String attrname, byte[] info) { 142 super(cp, attrname, info); 143 } 144 145 /** 146 * Constructs an empty 147 * <code>Runtime(In)VisibleAnnotations_attribute</code>. 148 * A new annotation can be later added to the created attribute 149 * by <code>setAnnotations()</code>. 150 * 151 * @param cp constant pool 152 * @param attrname attribute name (<code>visibleTag</code> or 153 * <code>invisibleTag</code>). 154 * @see #setAnnotations(Annotation[]) 155 */ AnnotationsAttribute(ConstPool cp, String attrname)156 public AnnotationsAttribute(ConstPool cp, String attrname) { 157 this(cp, attrname, new byte[] { 0, 0 }); 158 } 159 160 /** 161 * @param n the attribute name. 162 */ AnnotationsAttribute(ConstPool cp, int n, DataInputStream in)163 AnnotationsAttribute(ConstPool cp, int n, DataInputStream in) 164 throws IOException 165 { 166 super(cp, n, in); 167 } 168 169 /** 170 * Returns <code>num_annotations</code>. 171 */ numAnnotations()172 public int numAnnotations() { 173 return ByteArray.readU16bit(info, 0); 174 } 175 176 /** 177 * Copies this attribute and returns a new copy. 178 */ 179 @Override copy(ConstPool newCp, Map<String,String> classnames)180 public AttributeInfo copy(ConstPool newCp, Map<String,String> classnames) { 181 Copier copier = new Copier(info, constPool, newCp, classnames); 182 try { 183 copier.annotationArray(); 184 return new AnnotationsAttribute(newCp, getName(), copier.close()); 185 } 186 catch (Exception e) { 187 throw new RuntimeException(e); 188 } 189 } 190 191 /** 192 * Parses the annotations and returns a data structure representing 193 * the annotation with the specified type. See also 194 * <code>getAnnotations()</code> as to the returned data structure. 195 * 196 * @param type the annotation type. 197 * @return null if the specified annotation type is not included. 198 * @see #getAnnotations() 199 */ getAnnotation(String type)200 public Annotation getAnnotation(String type) { 201 Annotation[] annotations = getAnnotations(); 202 for (int i = 0; i < annotations.length; i++) { 203 if (annotations[i].getTypeName().equals(type)) 204 return annotations[i]; 205 } 206 207 return null; 208 } 209 210 /** 211 * Adds an annotation. If there is an annotation with the same type, 212 * it is removed before the new annotation is added. 213 * 214 * @param annotation the added annotation. 215 */ addAnnotation(Annotation annotation)216 public void addAnnotation(Annotation annotation) { 217 String type = annotation.getTypeName(); 218 Annotation[] annotations = getAnnotations(); 219 for (int i = 0; i < annotations.length; i++) { 220 if (annotations[i].getTypeName().equals(type)) { 221 annotations[i] = annotation; 222 setAnnotations(annotations); 223 return; 224 } 225 } 226 227 Annotation[] newlist = new Annotation[annotations.length + 1]; 228 System.arraycopy(annotations, 0, newlist, 0, annotations.length); 229 newlist[annotations.length] = annotation; 230 setAnnotations(newlist); 231 } 232 233 /** 234 * Removes an annotation by type. 235 * After removing an annotation, if {@link #numAnnotations()} returns 0, 236 * this annotations attribute has to be removed. 237 * 238 * @param type of annotation to remove 239 * @return whether an annotation with the given type has been removed 240 * @since 3.21 241 */ removeAnnotation(String type)242 public boolean removeAnnotation(String type) { 243 Annotation[] annotations = getAnnotations(); 244 for (int i = 0; i < annotations.length; i++) { 245 if (annotations[i].getTypeName().equals(type)) { 246 Annotation[] newlist = new Annotation[annotations.length - 1]; 247 System.arraycopy(annotations, 0, newlist, 0, i); 248 if (i < annotations.length - 1) { 249 System.arraycopy(annotations, i + 1, newlist, i, 250 annotations.length - i - 1); 251 } 252 setAnnotations(newlist); 253 return true; 254 } 255 } 256 return false; 257 } 258 259 /** 260 * Parses the annotations and returns a data structure representing 261 * that parsed annotations. Note that changes of the node values of the 262 * returned tree are not reflected on the annotations represented by 263 * this object unless the tree is copied back to this object by 264 * <code>setAnnotations()</code>. 265 * 266 * @see #setAnnotations(Annotation[]) 267 */ getAnnotations()268 public Annotation[] getAnnotations() { 269 try { 270 return new Parser(info, constPool).parseAnnotations(); 271 } 272 catch (Exception e) { 273 throw new RuntimeException(e); 274 } 275 } 276 277 /** 278 * Changes the annotations represented by this object according to 279 * the given array of <code>Annotation</code> objects. 280 * 281 * @param annotations the data structure representing the 282 * new annotations. 283 */ setAnnotations(Annotation[] annotations)284 public void setAnnotations(Annotation[] annotations) { 285 ByteArrayOutputStream output = new ByteArrayOutputStream(); 286 AnnotationsWriter writer = new AnnotationsWriter(output, constPool); 287 try { 288 int n = annotations.length; 289 writer.numAnnotations(n); 290 for (int i = 0; i < n; ++i) 291 annotations[i].write(writer); 292 293 writer.close(); 294 } 295 catch (IOException e) { 296 throw new RuntimeException(e); // should never reach here. 297 } 298 299 set(output.toByteArray()); 300 } 301 302 /** 303 * Changes the annotations. A call to this method is equivalent to: 304 * <pre>setAnnotations(new Annotation[] { annotation })</pre> 305 * 306 * @param annotation the data structure representing 307 * the new annotation. 308 */ setAnnotation(Annotation annotation)309 public void setAnnotation(Annotation annotation) { 310 setAnnotations(new Annotation[] { annotation }); 311 } 312 313 /** 314 * @param oldname a JVM class name. 315 * @param newname a JVM class name. 316 */ 317 @Override renameClass(String oldname, String newname)318 void renameClass(String oldname, String newname) { 319 Map<String,String> map = new HashMap<String,String>(); 320 map.put(oldname, newname); 321 renameClass(map); 322 } 323 324 @Override renameClass(Map<String,String> classnames)325 void renameClass(Map<String,String> classnames) { 326 Renamer renamer = new Renamer(info, getConstPool(), classnames); 327 try { 328 renamer.annotationArray(); 329 } catch (Exception e) { 330 throw new RuntimeException(e); 331 } 332 } 333 334 @Override getRefClasses(Map<String,String> classnames)335 void getRefClasses(Map<String,String> classnames) { renameClass(classnames); } 336 337 /** 338 * Returns a string representation of this object. 339 */ 340 @Override toString()341 public String toString() { 342 Annotation[] a = getAnnotations(); 343 StringBuilder sbuf = new StringBuilder(); 344 int i = 0; 345 while (i < a.length) { 346 sbuf.append(a[i++].toString()); 347 if (i != a.length) 348 sbuf.append(", "); 349 } 350 351 return sbuf.toString(); 352 } 353 354 static class Walker { 355 byte[] info; 356 Walker(byte[] attrInfo)357 Walker(byte[] attrInfo) { 358 info = attrInfo; 359 } 360 parameters()361 final void parameters() throws Exception { 362 int numParam = info[0] & 0xff; 363 parameters(numParam, 1); 364 } 365 parameters(int numParam, int pos)366 void parameters(int numParam, int pos) throws Exception { 367 for (int i = 0; i < numParam; ++i) 368 pos = annotationArray(pos); 369 } 370 annotationArray()371 final void annotationArray() throws Exception { 372 annotationArray(0); 373 } 374 annotationArray(int pos)375 final int annotationArray(int pos) throws Exception { 376 int num = ByteArray.readU16bit(info, pos); 377 return annotationArray(pos + 2, num); 378 } 379 annotationArray(int pos, int num)380 int annotationArray(int pos, int num) throws Exception { 381 for (int i = 0; i < num; ++i) 382 pos = annotation(pos); 383 384 return pos; 385 } 386 annotation(int pos)387 final int annotation(int pos) throws Exception { 388 int type = ByteArray.readU16bit(info, pos); 389 int numPairs = ByteArray.readU16bit(info, pos + 2); 390 return annotation(pos + 4, type, numPairs); 391 } 392 annotation(int pos, int type, int numPairs)393 int annotation(int pos, int type, int numPairs) throws Exception { 394 for (int j = 0; j < numPairs; ++j) 395 pos = memberValuePair(pos); 396 397 return pos; 398 } 399 400 /** 401 * {@code element_value_paris} 402 */ memberValuePair(int pos)403 final int memberValuePair(int pos) throws Exception { 404 int nameIndex = ByteArray.readU16bit(info, pos); 405 return memberValuePair(pos + 2, nameIndex); 406 } 407 408 /** 409 * {@code element_value_paris[]} 410 */ memberValuePair(int pos, int nameIndex)411 int memberValuePair(int pos, int nameIndex) throws Exception { 412 return memberValue(pos); 413 } 414 415 /** 416 * {@code element_value} 417 */ memberValue(int pos)418 final int memberValue(int pos) throws Exception { 419 int tag = info[pos] & 0xff; 420 if (tag == 'e') { 421 int typeNameIndex = ByteArray.readU16bit(info, pos + 1); 422 int constNameIndex = ByteArray.readU16bit(info, pos + 3); 423 enumMemberValue(pos, typeNameIndex, constNameIndex); 424 return pos + 5; 425 } 426 else if (tag == 'c') { 427 int index = ByteArray.readU16bit(info, pos + 1); 428 classMemberValue(pos, index); 429 return pos + 3; 430 } 431 else if (tag == '@') 432 return annotationMemberValue(pos + 1); 433 else if (tag == '[') { 434 int num = ByteArray.readU16bit(info, pos + 1); 435 return arrayMemberValue(pos + 3, num); 436 } 437 else { // primitive types or String. 438 int index = ByteArray.readU16bit(info, pos + 1); 439 constValueMember(tag, index); 440 return pos + 3; 441 } 442 } 443 444 /** 445 * {@code const_value_index} 446 */ constValueMember(int tag, int index)447 void constValueMember(int tag, int index) throws Exception {} 448 449 /** 450 * {@code enum_const_value} 451 */ enumMemberValue(int pos, int typeNameIndex, int constNameIndex)452 void enumMemberValue(int pos, int typeNameIndex, int constNameIndex) 453 throws Exception { 454 } 455 456 /** 457 * {@code class_info_index} 458 */ classMemberValue(int pos, int index)459 void classMemberValue(int pos, int index) throws Exception {} 460 461 /** 462 * {@code annotation_value} 463 */ annotationMemberValue(int pos)464 int annotationMemberValue(int pos) throws Exception { 465 return annotation(pos); 466 } 467 468 /** 469 * {@code array_value} 470 */ arrayMemberValue(int pos, int num)471 int arrayMemberValue(int pos, int num) throws Exception { 472 for (int i = 0; i < num; ++i) { 473 pos = memberValue(pos); 474 } 475 476 return pos; 477 } 478 } 479 480 static class Renamer extends Walker { 481 ConstPool cpool; 482 Map<String,String> classnames; 483 484 /** 485 * Constructs a renamer. It renames some class names 486 * into the new names specified by <code>map</code>. 487 * 488 * @param info the annotations attribute. 489 * @param cp the constant pool. 490 * @param map pairs of replaced and substituted class names. 491 * It can be null. 492 */ Renamer(byte[] info, ConstPool cp, Map<String,String> map)493 Renamer(byte[] info, ConstPool cp, Map<String,String> map) { 494 super(info); 495 cpool = cp; 496 classnames = map; 497 } 498 499 @Override annotation(int pos, int type, int numPairs)500 int annotation(int pos, int type, int numPairs) throws Exception { 501 renameType(pos - 4, type); 502 return super.annotation(pos, type, numPairs); 503 } 504 505 @Override enumMemberValue(int pos, int typeNameIndex, int constNameIndex)506 void enumMemberValue(int pos, int typeNameIndex, int constNameIndex) 507 throws Exception 508 { 509 renameType(pos + 1, typeNameIndex); 510 super.enumMemberValue(pos, typeNameIndex, constNameIndex); 511 } 512 513 @Override classMemberValue(int pos, int index)514 void classMemberValue(int pos, int index) throws Exception { 515 renameType(pos + 1, index); 516 super.classMemberValue(pos, index); 517 } 518 renameType(int pos, int index)519 private void renameType(int pos, int index) { 520 String name = cpool.getUtf8Info(index); 521 String newName = Descriptor.rename(name, classnames); 522 if (!name.equals(newName)) { 523 int index2 = cpool.addUtf8Info(newName); 524 ByteArray.write16bit(index2, info, pos); 525 } 526 } 527 } 528 529 static class Copier extends Walker { 530 ByteArrayOutputStream output; 531 AnnotationsWriter writer; 532 ConstPool srcPool, destPool; 533 Map<String,String> classnames; 534 535 /** 536 * Constructs a copier. This copier renames some class names 537 * into the new names specified by <code>map</code> when it copies 538 * an annotation attribute. 539 * 540 * @param info the source attribute. 541 * @param src the constant pool of the source class. 542 * @param dest the constant pool of the destination class. 543 * @param map pairs of replaced and substituted class names. 544 * It can be null. 545 */ Copier(byte[] info, ConstPool src, ConstPool dest, Map<String,String> map)546 Copier(byte[] info, ConstPool src, ConstPool dest, Map<String,String> map) { 547 this(info, src, dest, map, true); 548 } 549 Copier(byte[] info, ConstPool src, ConstPool dest, Map<String,String> map, boolean makeWriter)550 Copier(byte[] info, ConstPool src, ConstPool dest, Map<String,String> map, boolean makeWriter) { 551 super(info); 552 output = new ByteArrayOutputStream(); 553 if (makeWriter) 554 writer = new AnnotationsWriter(output, dest); 555 556 srcPool = src; 557 destPool = dest; 558 classnames = map; 559 } 560 close()561 byte[] close() throws IOException { 562 writer.close(); 563 return output.toByteArray(); 564 } 565 566 @Override parameters(int numParam, int pos)567 void parameters(int numParam, int pos) throws Exception { 568 writer.numParameters(numParam); 569 super.parameters(numParam, pos); 570 } 571 572 @Override annotationArray(int pos, int num)573 int annotationArray(int pos, int num) throws Exception { 574 writer.numAnnotations(num); 575 return super.annotationArray(pos, num); 576 } 577 578 @Override annotation(int pos, int type, int numPairs)579 int annotation(int pos, int type, int numPairs) throws Exception { 580 writer.annotation(copyType(type), numPairs); 581 return super.annotation(pos, type, numPairs); 582 } 583 584 @Override memberValuePair(int pos, int nameIndex)585 int memberValuePair(int pos, int nameIndex) throws Exception { 586 writer.memberValuePair(copy(nameIndex)); 587 return super.memberValuePair(pos, nameIndex); 588 } 589 590 @Override constValueMember(int tag, int index)591 void constValueMember(int tag, int index) throws Exception { 592 writer.constValueIndex(tag, copy(index)); 593 super.constValueMember(tag, index); 594 } 595 596 @Override enumMemberValue(int pos, int typeNameIndex, int constNameIndex)597 void enumMemberValue(int pos, int typeNameIndex, int constNameIndex) 598 throws Exception 599 { 600 writer.enumConstValue(copyType(typeNameIndex), copy(constNameIndex)); 601 super.enumMemberValue(pos, typeNameIndex, constNameIndex); 602 } 603 604 @Override classMemberValue(int pos, int index)605 void classMemberValue(int pos, int index) throws Exception { 606 writer.classInfoIndex(copyType(index)); 607 super.classMemberValue(pos, index); 608 } 609 610 @Override annotationMemberValue(int pos)611 int annotationMemberValue(int pos) throws Exception { 612 writer.annotationValue(); 613 return super.annotationMemberValue(pos); 614 } 615 616 @Override arrayMemberValue(int pos, int num)617 int arrayMemberValue(int pos, int num) throws Exception { 618 writer.arrayValue(num); 619 return super.arrayMemberValue(pos, num); 620 } 621 622 /** 623 * Copies a constant pool entry into the destination constant pool 624 * and returns the index of the copied entry. 625 * 626 * @param srcIndex the index of the copied entry into the source 627 * constant pool. 628 * @return the index of the copied item into the destination 629 * constant pool. 630 */ copy(int srcIndex)631 int copy(int srcIndex) { 632 return srcPool.copy(srcIndex, destPool, classnames); 633 } 634 635 /** 636 * Copies a constant pool entry into the destination constant pool 637 * and returns the index of the copied entry. That entry must be 638 * a Utf8Info representing a class name in the L<class name>; form. 639 * 640 * @param srcIndex the index of the copied entry into the source 641 * constant pool. 642 * @return the index of the copied item into the destination 643 * constant pool. 644 */ copyType(int srcIndex)645 int copyType(int srcIndex) { 646 String name = srcPool.getUtf8Info(srcIndex); 647 String newName = Descriptor.rename(name, classnames); 648 return destPool.addUtf8Info(newName); 649 } 650 } 651 652 static class Parser extends Walker { 653 ConstPool pool; 654 Annotation[][] allParams; // all parameters 655 Annotation[] allAnno; // all annotations 656 Annotation currentAnno; // current annotation 657 MemberValue currentMember; // current member 658 659 /** 660 * Constructs a parser. This parser constructs a parse tree of 661 * the annotations. 662 * 663 * @param info the attribute. 664 * @param src the constant pool. 665 */ Parser(byte[] info, ConstPool cp)666 Parser(byte[] info, ConstPool cp) { 667 super(info); 668 pool = cp; 669 } 670 parseParameters()671 Annotation[][] parseParameters() throws Exception { 672 parameters(); 673 return allParams; 674 } 675 parseAnnotations()676 Annotation[] parseAnnotations() throws Exception { 677 annotationArray(); 678 return allAnno; 679 } 680 parseMemberValue()681 MemberValue parseMemberValue() throws Exception { 682 memberValue(0); 683 return currentMember; 684 } 685 686 @Override parameters(int numParam, int pos)687 void parameters(int numParam, int pos) throws Exception { 688 Annotation[][] params = new Annotation[numParam][]; 689 for (int i = 0; i < numParam; ++i) { 690 pos = annotationArray(pos); 691 params[i] = allAnno; 692 } 693 694 allParams = params; 695 } 696 697 @Override annotationArray(int pos, int num)698 int annotationArray(int pos, int num) throws Exception { 699 Annotation[] array = new Annotation[num]; 700 for (int i = 0; i < num; ++i) { 701 pos = annotation(pos); 702 array[i] = currentAnno; 703 } 704 705 allAnno = array; 706 return pos; 707 } 708 709 @Override annotation(int pos, int type, int numPairs)710 int annotation(int pos, int type, int numPairs) throws Exception { 711 currentAnno = new Annotation(type, pool); 712 return super.annotation(pos, type, numPairs); 713 } 714 715 @Override memberValuePair(int pos, int nameIndex)716 int memberValuePair(int pos, int nameIndex) throws Exception { 717 pos = super.memberValuePair(pos, nameIndex); 718 currentAnno.addMemberValue(nameIndex, currentMember); 719 return pos; 720 } 721 722 @Override constValueMember(int tag, int index)723 void constValueMember(int tag, int index) throws Exception { 724 MemberValue m; 725 ConstPool cp = pool; 726 switch (tag) { 727 case 'B' : 728 m = new ByteMemberValue(index, cp); 729 break; 730 case 'C' : 731 m = new CharMemberValue(index, cp); 732 break; 733 case 'D' : 734 m = new DoubleMemberValue(index, cp); 735 break; 736 case 'F' : 737 m = new FloatMemberValue(index, cp); 738 break; 739 case 'I' : 740 m = new IntegerMemberValue(index, cp); 741 break; 742 case 'J' : 743 m = new LongMemberValue(index, cp); 744 break; 745 case 'S' : 746 m = new ShortMemberValue(index, cp); 747 break; 748 case 'Z' : 749 m = new BooleanMemberValue(index, cp); 750 break; 751 case 's' : 752 m = new StringMemberValue(index, cp); 753 break; 754 default : 755 throw new RuntimeException("unknown tag:" + tag); 756 } 757 758 currentMember = m; 759 super.constValueMember(tag, index); 760 } 761 762 @Override enumMemberValue(int pos, int typeNameIndex, int constNameIndex)763 void enumMemberValue(int pos, int typeNameIndex, int constNameIndex) 764 throws Exception 765 { 766 currentMember = new EnumMemberValue(typeNameIndex, 767 constNameIndex, pool); 768 super.enumMemberValue(pos, typeNameIndex, constNameIndex); 769 } 770 771 @Override classMemberValue(int pos, int index)772 void classMemberValue(int pos, int index) throws Exception { 773 currentMember = new ClassMemberValue(index, pool); 774 super.classMemberValue(pos, index); 775 } 776 777 @Override annotationMemberValue(int pos)778 int annotationMemberValue(int pos) throws Exception { 779 Annotation anno = currentAnno; 780 pos = super.annotationMemberValue(pos); 781 currentMember = new AnnotationMemberValue(currentAnno, pool); 782 currentAnno = anno; 783 return pos; 784 } 785 786 @Override arrayMemberValue(int pos, int num)787 int arrayMemberValue(int pos, int num) throws Exception { 788 ArrayMemberValue amv = new ArrayMemberValue(pool); 789 MemberValue[] elements = new MemberValue[num]; 790 for (int i = 0; i < num; ++i) { 791 pos = memberValue(pos); 792 elements[i] = currentMember; 793 } 794 795 amv.setValue(elements); 796 currentMember = amv; 797 return pos; 798 } 799 } 800 } 801