1 /***************************************************************************************
2 * Copyright (c) Jonas Bon?r, Alexandre Vasseur. All rights reserved. *
3 * http://aspectwerkz.codehaus.org *
4 * ---------------------------------------------------------------------------------- *
5 * The software in this package is published under the terms of the LGPL license *
6 * a copy of which has been included with this distribution in the license.txt file. *
7 **************************************************************************************/
8 package org.codehaus.aspectwerkz.annotation.instrumentation.asm;
9
10 import org.objectweb.asm.attrs.Annotation;
11 import org.objectweb.asm.attrs.RuntimeInvisibleAnnotations;
12 import org.objectweb.asm.Attribute;
13 import org.codehaus.aspectwerkz.util.Base64;
14 import org.codehaus.aspectwerkz.util.UnbrokenObjectInputStream;
15 import org.codehaus.aspectwerkz.annotation.AnnotationInfo;
16 import org.codehaus.aspectwerkz.exception.WrappedRuntimeException;
17
18 import java.io.ByteArrayInputStream;
19
20 /***
21 * Helper class to wrap a custom annotation proxy (1.3/1.4 javadoc annotation) in a RuntimeInvisibleAnnotations.
22 * <br/>
23 * The proxy is wrapped in a AnnotationInfo object which is serialized
24 * and base64 encoded (ASM issue on array types in RIV).
25 *
26 * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur</a>
27 */
28 public class CustomAttributeHelper {
29
30 /***
31 * Annotation parameter - as if it was a single value Tiger annotation
32 */
33 private final static String VALUE = "value";
34
35 /***
36 * Extract the AnnotationInfo from the bytecode Annotation representation.
37 *
38 * @param annotation must be a valid RIV, of type CustomAttribute.TYPE
39 * @return
40 */
41 public static AnnotationInfo extractCustomAnnotation(final Annotation annotation) {
42 byte[] bytes = Base64.decode((String) ((Object[]) annotation.elementValues.get(0))[1]);
43 return extractCustomAnnotation(bytes);
44 }
45
46 /***
47 * Extract the AnnotationInfo from the base64 encoded serialized version.
48 *
49 * @param bytes
50 * @return
51 */
52 private static AnnotationInfo extractCustomAnnotation(final byte[] bytes) {
53 try {
54 Object userAnnotation = new UnbrokenObjectInputStream(new ByteArrayInputStream(bytes)).readObject();
55 if (userAnnotation instanceof AnnotationInfo) {
56 return (AnnotationInfo)userAnnotation;
57 } else {
58
59 throw new RuntimeException(
60 "Custom annotation is not wrapped in AnnotationInfo: " + userAnnotation.getClass().getName() +
61 " [" + AnnotationInfo.class.getClassLoader().toString() + " / " +
62 userAnnotation.getClass().getClassLoader().toString() + " / " +
63 Thread.currentThread().getContextClassLoader()
64 );
65 }
66 } catch (Exception e) {
67 throw new WrappedRuntimeException(e);
68 }
69 }
70
71 /***
72 * Create an Annotation bytecode representation from the serialized version of the custom annotation proxy
73 *
74 * @param bytes
75 * @return
76 */
77 public static Annotation createCustomAnnotation(final byte[] bytes) {
78 Annotation annotation = new Annotation();
79 annotation.type = CustomAttribute.TYPE;
80 annotation.add(VALUE, Base64.encodeBytes(bytes));
81 return annotation;
82 }
83
84 /***
85 * Helper method to find the first RuntimeInvisibleAnnotations attribute in an Attribute chain.
86 * <br/>If no such RIV exists, a new one is created (empty) and added last in the chain.
87 * <br/>If the chain is null, a new sole RIV (empty) is created
88 *
89 * @param attribute
90 * @return the RuntimeInvisibleAnnotations to add Annotation to
91 */
92 public static RuntimeInvisibleAnnotations linkRuntimeInvisibleAnnotations(final Attribute attribute) {
93 RuntimeInvisibleAnnotations runtimeInvisibleAnnotations = null;
94 Attribute lastAttribute = attribute;
95 for (Attribute loop = attribute; loop != null; loop = loop.next) {
96 lastAttribute = loop;
97 if (loop instanceof RuntimeInvisibleAnnotations) {
98 return runtimeInvisibleAnnotations = (RuntimeInvisibleAnnotations) loop;
99 }
100 }
101
102 runtimeInvisibleAnnotations = new RuntimeInvisibleAnnotations();
103 runtimeInvisibleAnnotations.next = null;
104 if (attribute != null) {
105
106 lastAttribute.next = runtimeInvisibleAnnotations;
107 } else {
108
109 }
110 return runtimeInvisibleAnnotations;
111 }
112 }