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