001 002 package net.sourceforge.retroweaver.runtime.java.lang.annotation; 003 004 import java.io.IOException; 005 import java.io.InputStream; 006 import java.lang.reflect.Array; 007 import java.lang.reflect.Method; 008 import java.util.ArrayList; 009 import java.util.HashMap; 010 import java.util.Hashtable; 011 import java.util.LinkedList; 012 import java.util.List; 013 import java.util.Map; 014 015 import net.sourceforge.retroweaver.runtime.java.lang.Enum; 016 017 import org.objectweb.asm.AnnotationVisitor; 018 import org.objectweb.asm.Attribute; 019 import org.objectweb.asm.ClassReader; 020 import org.objectweb.asm.ClassVisitor; 021 import org.objectweb.asm.FieldVisitor; 022 import org.objectweb.asm.Label; 023 import org.objectweb.asm.MethodAdapter; 024 import org.objectweb.asm.MethodVisitor; 025 import org.objectweb.asm.Type; 026 027 /** 028 * The Annotation Information Block. 029 * 030 * This is the runtime data structure that holds all of the annotation data in 031 * a form that Retroweaver's runtime can use easily. At weave time, we create 032 * a public static transient field named [ANNOTATIONS_FIELD] of this type. At 033 * runtime, we parse the class file, read the annotation data, and populate this 034 * data structure. 035 * 036 * ( Method parameter annotations appear in the same order as method parameters, 037 * and each parameter gets its own list of Annotations ) 038 * 039 * @author Toby Reyelts 040 * 041 */ 042 public class AIB implements ClassVisitor { 043 044 private Class class_; 045 private Map<String,Annotation> classAnnotations; 046 private Map<String,Map<String,Annotation>> methodAnnotations; 047 private Map<String,ArrayList<Map<String,Annotation>>> methodParameterAnnotations; 048 private Map<String,Map<String,Annotation>> fieldAnnotations; 049 private Map<String,Annotation> inheritedClassAnnotations; 050 private Map<String,Object> cachedMethodDefaults; 051 052 private AIB(Class c) { 053 classAnnotations = new HashMap<String,Annotation>(); 054 methodAnnotations = new HashMap<String,Map<String,Annotation>>(); 055 methodParameterAnnotations = new HashMap<String,ArrayList<Map<String,Annotation>>>(); 056 fieldAnnotations = new HashMap<String,Map<String,Annotation>>(); 057 inheritedClassAnnotations = new HashMap<String,Annotation>(); 058 059 this.class_ = c; 060 061 readClassStream(c.getName(), this); 062 } 063 064 private void readClassStream(final String name, final ClassVisitor cv) { 065 String resource = "/" + name.replace('.', '/') + ".class"; 066 InputStream classStream = class_.getResourceAsStream(resource); 067 try { 068 ClassReader r = new ClassReader(classStream); 069 r.accept(cv, ClassReader.SKIP_CODE + ClassReader.SKIP_DEBUG 070 + ClassReader.SKIP_FRAMES); 071 072 Class parent = class_.getSuperclass(); 073 if (parent != null) { 074 AIB parentAib = getAib(parent); 075 for(Map.Entry<String, Annotation> entry: parentAib.inheritedClassAnnotations.entrySet()) { 076 inheritedClassAnnotations.put(entry.getKey(), entry.getValue()); 077 } 078 } 079 // add the local annotations 080 for(Map.Entry<String, Annotation> entry: classAnnotations.entrySet()) { 081 inheritedClassAnnotations.put(entry.getKey(), entry.getValue()); 082 } 083 } catch (IOException e) { 084 // Shouldn't generally happen 085 throw new AnnotationFormatError( 086 "[Retroweaver] Unable to read annotation data for: " + name, e); 087 } finally { 088 try { 089 if (classStream != null) { 090 classStream.close(); 091 } 092 } catch (IOException e) { // NOPMD by xlv 093 } 094 } 095 } 096 097 private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[]{}; 098 099 private static final Annotation[][] EMPTY_ANNOTATION_ARRAY_ARRAY = new Annotation[][]{}; 100 101 public Annotation[] getClassAnnotations() { 102 return inheritedClassAnnotations.values().toArray( EMPTY_ANNOTATION_ARRAY ); 103 } 104 105 public Annotation[] getDeclaredClassAnnotations() { 106 return classAnnotations.values().toArray( EMPTY_ANNOTATION_ARRAY ); 107 } 108 109 public <T extends Annotation> T getClassAnnotation(final Class<T> annotationType) { 110 return (T) inheritedClassAnnotations.get(annotationType.getName()); 111 } 112 113 public Annotation[] getFieldAnnotations(final String fieldName) { 114 final Map<String,Annotation> annotations = fieldAnnotations.get( fieldName ); 115 return annotations.values().toArray( EMPTY_ANNOTATION_ARRAY ); 116 } 117 118 public <T extends Annotation> T getFieldAnnotation(final String fieldName, final Class<T> annotationType) { 119 final Map<String,Annotation> annotations = fieldAnnotations.get( fieldName ); 120 return (T) annotations.get(annotationType.getName()); 121 } 122 123 private String getMethodIdentifier(final String methodName, final Class[] parameterTypes, final Class returnType) { 124 final StringBuilder b = new StringBuilder(methodName); 125 b.append('('); 126 for (Class c: parameterTypes) { 127 b.append(Type.getDescriptor(c)); 128 } 129 b.append(')').append(Type.getDescriptor(returnType)); 130 return b.toString(); 131 132 } 133 public Annotation[] getMethodAnnotations(final String methodName, final Class[] parameterTypes, final Class returnType) { 134 final Map<String,Annotation> annotations = methodAnnotations.get(getMethodIdentifier(methodName, parameterTypes, returnType)); 135 if (annotations == null) { 136 return EMPTY_ANNOTATION_ARRAY; 137 } 138 return annotations.values().toArray( EMPTY_ANNOTATION_ARRAY ); 139 } 140 141 public <T extends Annotation> T getMethodAnnotation(final String methodName, final Class[] parameterTypes, final Class returnType, final Class<T> annotationType) { 142 final Map<String,Annotation> annotations = methodAnnotations.get(getMethodIdentifier(methodName, parameterTypes, returnType)); 143 if (annotations == null) { 144 return null; 145 } 146 return (T) annotations.get(annotationType.getName()); 147 } 148 149 private Map<String, Object> getMethodDefaults() { 150 assert(class_.isAnnotation()); 151 152 if (cachedMethodDefaults == null) { 153 DefaultValueVisitor v = new DefaultValueVisitor(); 154 cachedMethodDefaults = v.parseAttributes(class_.getName()); 155 } 156 157 return cachedMethodDefaults; 158 } 159 160 private static final Method cloneMethod; 161 162 static { 163 try { 164 cloneMethod = Object.class.getDeclaredMethod("clone", new Class[0]); 165 cloneMethod.setAccessible(true); 166 } catch (NoSuchMethodException e) { 167 throw new RuntimeException(e.getMessage()); 168 } 169 } 170 171 public Object getDefaultValue(final String methodName) { 172 assert (class_.isAnnotation()); 173 174 Object o = getMethodDefaults().get(methodName); 175 if (o == null) { 176 return null; 177 } else if (o.getClass().isArray()) { 178 try { 179 o = cloneMethod.invoke(o); 180 } catch (Exception e) { 181 throw new RuntimeException(e.getMessage()); 182 } 183 } 184 return o; 185 } 186 187 public Annotation[][] getMethodParameterAnnotations(final String methodName, final Class[] parameterTypes, final Class returnType) { 188 ArrayList<Map<String, Annotation>> annotations = methodParameterAnnotations.get(getMethodIdentifier(methodName, parameterTypes, returnType)); 189 190 if (annotations == null) { 191 return EMPTY_ANNOTATION_ARRAY_ARRAY; // NOPMD by xlv 192 } 193 194 if (annotations.size() != parameterTypes.length) { 195 throw new AnnotationFormatError("inconsistent parameter count"); 196 } 197 198 Annotation[][] a = new Annotation[parameterTypes.length][]; 199 200 for(int i = 0; i < parameterTypes.length; i++) { 201 Map<String, Annotation> map = annotations.get(i); 202 203 a[i] = map.values().toArray(EMPTY_ANNOTATION_ARRAY); 204 } 205 206 return a; 207 } 208 209 private static final Map<Class, AIB> classDescriptors = new Hashtable<Class, AIB>(); 210 211 /** 212 * Returns the AIB for the class. 213 */ 214 public static AIB getAib(final Class c) { 215 synchronized (c) { 216 AIB aib = classDescriptors.get(c); 217 if (aib == null) { 218 aib = new AIB(c); 219 classDescriptors.put(c, aib); 220 } 221 return aib; 222 } 223 } 224 225 public AnnotationVisitor visitAnnotation(String desc, boolean visible) { 226 if (!visible) { return EMPTY_VISITOR; } 227 228 return new TopLevelAnnotation(desc, classAnnotations); 229 } 230 231 public FieldVisitor visitField(final int access, final String fieldName, 232 final String desc, final String signature, final Object value) { 233 return new FieldVisitor() { 234 235 Map<String,Annotation> annotations = new HashMap<String,Annotation>(); 236 237 public AnnotationVisitor visitAnnotation(String desc, 238 boolean visible) { 239 if (!visible) { return EMPTY_VISITOR; } 240 241 return new TopLevelAnnotation(desc, annotations); 242 } 243 244 public void visitAttribute(Attribute attr) { 245 // EMPTY 246 } 247 248 public void visitEnd() { 249 fieldAnnotations.put(fieldName, annotations); 250 } 251 }; 252 } 253 254 public MethodVisitor visitMethod(final int access, final String methodName, 255 final String desc, final String signature, final String[] exceptions) { 256 return new MethodAdapter(EMPTY_VISITOR) { 257 258 Map<String,Annotation> ma = new HashMap<String,Annotation>(); 259 ArrayList<Map<String, Annotation>> pa = new ArrayList<Map<String, Annotation>>(); 260 261 public AnnotationVisitor visitAnnotationDefault() { 262 return EMPTY_VISITOR; 263 } 264 265 public AnnotationVisitor visitAnnotation(String desc, 266 boolean visible) { 267 if (!visible) { return EMPTY_VISITOR; } 268 269 return new TopLevelAnnotation(desc, ma); 270 } 271 272 public AnnotationVisitor visitParameterAnnotation(int parameter, 273 String desc, boolean visible) { 274 if (!visible) { return EMPTY_VISITOR; } 275 276 Map<String, Annotation> map; 277 if (parameter < pa.size()) { 278 map = pa.get(parameter); 279 } else { 280 map = new HashMap<String, Annotation>(); 281 pa.add(parameter, map); 282 } 283 284 return new TopLevelAnnotation(desc, map); 285 } 286 287 public void visitEnd() { 288 String name = methodName + desc; 289 methodAnnotations.put(name, ma); 290 methodParameterAnnotations.put(name, pa); 291 } 292 }; 293 } 294 295 public void visit(int version, int access, String name, String signature, 296 String superName, String[] interfaces) { 297 // EMPTY 298 } 299 300 public void visitSource(String source, String debug) { 301 // EMPTY 302 } 303 304 public void visitOuterClass(String owner, String name, String desc) { 305 // EMPTY 306 } 307 308 public void visitAttribute(Attribute attr) { 309 // EMPTY 310 } 311 312 public void visitInnerClass(String name, String outerName, 313 String innerName, int access) { 314 // EMPTY 315 } 316 317 public void visitEnd() { 318 // EMPTY 319 } 320 321 class DefaultValueVisitor implements ClassVisitor { 322 323 private final Map<String,Object> attributes = new HashMap<String,Object>(); 324 325 Map<String,Object> parseAttributes(String className) { 326 readClassStream(className, this); 327 328 return attributes; 329 } 330 331 public AnnotationVisitor visitAnnotation(String desc, boolean visible) { 332 return EMPTY_VISITOR; 333 } 334 335 public FieldVisitor visitField(final int access, final String name, 336 final String desc, final String signature, final Object value) { 337 return EMPTY_VISITOR; 338 } 339 340 public MethodVisitor visitMethod(final int access, final String methodName, 341 final String desc, final String signature, final String[] exceptions) { 342 return new MethodAdapter(EMPTY_VISITOR) { 343 344 public AnnotationVisitor visitAnnotationDefault() { 345 // remove leading () 346 String type = desc.substring(2); 347 348 return new DefaultAnnotation(methodName, type, attributes); 349 } 350 351 public AnnotationVisitor visitAnnotation(String desc, 352 boolean visible) { 353 return EMPTY_VISITOR; 354 } 355 356 public AnnotationVisitor visitParameterAnnotation(int parameter, 357 String desc, boolean visible) { 358 return EMPTY_VISITOR; 359 } 360 }; 361 } 362 363 public void visit(int version, int access, String name, String signature, 364 String superName, String[] interfaces) { 365 // EMPTY 366 } 367 368 public void visitSource(String source, String debug) { 369 // EMPTY 370 } 371 372 public void visitOuterClass(String owner, String name, String desc) { 373 // EMPTY 374 } 375 376 public void visitAttribute(Attribute attr) { 377 // EMPTY 378 } 379 380 public void visitInnerClass(String name, String outerName, 381 String innerName, int access) { 382 // EMPTY 383 } 384 385 public void visitEnd() { 386 // EMPTY 387 } 388 } 389 390 abstract class AbstractAnnotationVisitor implements AnnotationVisitor { 391 392 protected final AbstractAnnotationVisitor parent; 393 394 protected final String className; 395 396 AbstractAnnotationVisitor(AbstractAnnotationVisitor parent, String className) { 397 this.parent = parent; 398 this.className = className; 399 } 400 401 protected Class getClass(String name) { 402 try { 403 return Class.forName(name, true, class_.getClassLoader()); 404 } catch (ClassNotFoundException e) { 405 throw new AnnotationFormatError( 406 "[Retroweaver] Unable to find class: " + name, e); 407 } 408 } 409 410 protected Annotation createAnnotation(String className, Map<String, Object>attributes) { 411 String internalName = Type.getType(className).getClassName(); 412 Class<? extends Annotation> type = (Class<? extends Annotation>) getClass(internalName); 413 Annotation a = AnnotationImpl.createAnnotation(type, attributes); 414 415 return a; 416 } 417 418 private Object getEnumValue(final String desc, final String value) { 419 String name = Type.getType(desc).getClassName(); 420 Class c = getClass(name); 421 return Enum.valueOf(c, value); 422 } 423 424 abstract void insertValue(String name, Object value); 425 426 public void visit(String name, Object value) { 427 Object v; 428 if (value instanceof Type) { 429 Type t = (Type) value; 430 v = getClass(t.getClassName()); 431 } else { 432 v = value; 433 } 434 435 insertValue(name, v); 436 } 437 438 public void visitEnum(String name, String desc, String value) { 439 insertValue(name, getEnumValue(desc, value)); 440 } 441 442 public AnnotationVisitor visitAnnotation(String name, String desc) { 443 return new NestedAnnotation(this, desc); 444 } 445 446 } 447 448 private class ArrayAnnotation extends AbstractAnnotationVisitor { 449 450 ArrayAnnotation(AbstractAnnotationVisitor parent, String className, String type) { 451 super(parent, className); 452 this.type = type; 453 } 454 455 private final String type; 456 457 private final List<Object> values = new LinkedList<Object>(); 458 459 void insertValue(String name, Object value) { 460 values.add(value); 461 } 462 463 public AnnotationVisitor visitArray(String name) { 464 throw new UnsupportedOperationException("Nested arrays are not allowed"); 465 } 466 467 public void visitEnd() { 468 Class c = getClass(type.replace('/', '.')); 469 c = c.getComponentType(); 470 471 Object a = Array.newInstance(c, values.size()); 472 if (!values.isEmpty()) { 473 a = values.toArray((Object[]) a); 474 } 475 476 parent.insertValue(className, a); 477 } 478 } 479 480 private class NestedAnnotation extends AbstractAnnotationVisitor { 481 482 NestedAnnotation(AbstractAnnotationVisitor parent, String className) { 483 super(parent, className); 484 } 485 486 private final Map<String, Object> attributes = new HashMap<String, Object>(); 487 488 void insertValue(String name, Object value) { 489 attributes.put(name, value); 490 } 491 492 public AnnotationVisitor visitArray(String name) { 493 throw new UnsupportedOperationException(); 494 } 495 496 public void visitEnd() { 497 Annotation annotation = createAnnotation(className, attributes); 498 499 parent.insertValue(className, annotation); 500 } 501 502 } 503 504 private class DefaultAnnotation extends AbstractAnnotationVisitor { 505 506 DefaultAnnotation(String className, String type, Map<String, Object> attributes) { 507 super(null, className); 508 this.type = type; 509 this.attributes = attributes; 510 } 511 512 private final String type; 513 514 private final Map<String, Object> attributes; 515 516 void insertValue(String name, Object value) { 517 attributes.put(className, value); 518 } 519 520 public AnnotationVisitor visitArray(String name) { 521 return new ArrayAnnotation(this, className, type); 522 } 523 524 public AnnotationVisitor visitAnnotation(String name, String desc) { 525 return new NestedAnnotation(this, className); 526 } 527 528 public void visitEnd() { 529 } 530 531 } 532 533 private class TopLevelAnnotation extends AbstractAnnotationVisitor { 534 535 TopLevelAnnotation(String className, Map<String,Annotation> annotations) { 536 super(null, className); 537 538 this.annotations = annotations; 539 540 // first get default values 541 // then visitor methods are used to fill the custom settings 542 String type = Type.getType(className).getClassName(); 543 attributes = new HashMap<String, Object>(getAib(getClass(type)).getMethodDefaults()); 544 } 545 546 private final Map<String,Annotation> annotations; 547 548 private final Map<String, Object> attributes; 549 550 private String getClassNameFromInternalName(final String name) { 551 if (name.charAt(0) != 'L') { 552 return name; 553 } 554 555 return name.replace('/', '.').substring(1, name.length()-1); 556 } 557 558 void insertValue(String name, Object value) { 559 String key = getClassNameFromInternalName(name); 560 attributes.put(key, value); 561 } 562 563 public AnnotationVisitor visitArray(String name) { 564 try { 565 String type = Type.getType(className).getClassName(); 566 Method m = Class.forName(type).getMethod(name, new Class[0]); 567 type = m.getReturnType().getName(); 568 return new ArrayAnnotation(this, name, type); 569 } catch (Exception e) { 570 throw new AnnotationFormatError(e); 571 } 572 } 573 574 public void visitEnd() { 575 Annotation annotation = createAnnotation(className, attributes); 576 577 String key = getClassNameFromInternalName(className); 578 annotations.put(key, annotation); 579 } 580 581 } 582 583 public static final AIBEmptyVisitor EMPTY_VISITOR = new AIBEmptyVisitor(); 584 585 public static final class AIBEmptyVisitor implements ClassVisitor, FieldVisitor, 586 MethodVisitor, AnnotationVisitor { 587 588 public void visit(final int version, final int access, 589 final String name, final String signature, 590 final String superName, final String[] interfaces) { 591 } 592 593 public void visitSource(final String source, final String debug) { 594 } 595 596 public void visitOuterClass(final String owner, final String name, 597 final String desc) { 598 } 599 600 public AnnotationVisitor visitAnnotation(final String desc, 601 final boolean visible) { 602 return this; 603 } 604 605 public void visitAttribute(final Attribute attr) { 606 } 607 608 public void visitInnerClass(final String name, final String outerName, 609 final String innerName, final int access) { 610 } 611 612 public FieldVisitor visitField(final int access, final String name, 613 final String desc, final String signature, final Object value) { 614 return this; 615 } 616 617 public MethodVisitor visitMethod(final int access, final String name, 618 final String desc, final String signature, 619 final String[] exceptions) { 620 return this; 621 } 622 623 public void visitEnd() { 624 } 625 626 public AnnotationVisitor visitAnnotationDefault() { 627 return this; 628 } 629 630 public AnnotationVisitor visitParameterAnnotation(final int parameter, 631 final String desc, final boolean visible) { 632 return this; 633 } 634 635 public void visitCode() { 636 } 637 638 public void visitFrame(final int type, final int nLocal, 639 final Object[] local, final int nStack, final Object[] stack) { 640 } 641 642 public void visitInsn(final int opcode) { 643 } 644 645 public void visitIntInsn(final int opcode, final int operand) { 646 } 647 648 public void visitVarInsn(final int opcode, final int var) { 649 } 650 651 public void visitTypeInsn(final int opcode, final String desc) { 652 } 653 654 public void visitFieldInsn(final int opcode, final String owner, 655 final String name, final String desc) { 656 } 657 658 public void visitMethodInsn(final int opcode, final String owner, 659 final String name, final String desc) { 660 } 661 662 public void visitJumpInsn(final int opcode, final Label label) { 663 } 664 665 public void visitLabel(final Label label) { 666 } 667 668 public void visitLdcInsn(final Object cst) { 669 } 670 671 public void visitIincInsn(final int var, final int increment) { 672 } 673 674 public void visitTableSwitchInsn(final int min, final int max, 675 final Label dflt, final Label labels[]) { 676 } 677 678 public void visitLookupSwitchInsn(final Label dflt, final int keys[], 679 final Label labels[]) { 680 } 681 682 public void visitMultiANewArrayInsn(final String desc, final int dims) { 683 } 684 685 public void visitTryCatchBlock(final Label start, final Label end, 686 final Label handler, final String type) { 687 } 688 689 public void visitLocalVariable(final String name, final String desc, 690 final String signature, final Label start, final Label end, 691 final int index) { 692 } 693 694 public void visitLineNumber(final int line, final Label start) { 695 } 696 697 public void visitMaxs(final int maxStack, final int maxLocals) { 698 } 699 700 public void visit(final String name, final Object value) { 701 } 702 703 public void visitEnum(final String name, final String desc, 704 final String value) { 705 } 706 707 public AnnotationVisitor visitAnnotation(final String name, 708 final String desc) { 709 return this; 710 } 711 712 public AnnotationVisitor visitArray(final String name) { 713 return this; 714 } 715 } 716 717 } 718