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.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 * @param bytes
49 * @return
50 */
51 public static AnnotationInfo extractCustomAnnotation(final byte[] bytes) {
52 try {
53 Object userAnnotation = new UnbrokenObjectInputStream(new ByteArrayInputStream(bytes)).readObject();
54 if (userAnnotation instanceof AnnotationInfo) {
55 return (AnnotationInfo)userAnnotation;
56 } else {
57
58 throw new RuntimeException("Custom annotation is not wrapped in AnnotationInfo: "
59 + userAnnotation.getClass().getName()
60 + " in " + userAnnotation.getClass().getClassLoader() + ". AnnotationInfo is in "
61 + AnnotationInfo.class.getClassLoader());
62 }
63 } catch (Exception e) {
64 throw new WrappedRuntimeException(e);
65 }
66 }
67
68 /***
69 * Create an Annotation bytecode representation from the serialized version of the custom annotation proxy
70 * @param bytes
71 * @return
72 */
73 public static Annotation createCustomAnnotation(final byte[] bytes) {
74 Annotation annotation = new Annotation();
75 annotation.type = CustomAttribute.TYPE;
76 annotation.add(VALUE, Base64.encodeBytes(bytes));
77 return annotation;
78 }
79
80 /***
81 * Helper method to find the first RuntimeInvisibleAnnotations attribute in an Attribute chain.
82 * <br/>If no such RIV exists, a new one is created (empty) and added last in the chain.
83 * <br/>If the chain is null, a new sole RIV (empty) is created
84 *
85 * @param attribute
86 * @return the RuntimeInvisibleAnnotations to add Annotation to
87 */
88 public static RuntimeInvisibleAnnotations linkRuntimeInvisibleAnnotations(final Attribute attribute) {
89 RuntimeInvisibleAnnotations runtimeInvisibleAnnotations = null;
90 Attribute lastAttribute = attribute;
91 for (Attribute loop = attribute; loop != null; loop = loop.next) {
92 lastAttribute = loop;
93 if (loop instanceof RuntimeInvisibleAnnotations) {
94 return runtimeInvisibleAnnotations = (RuntimeInvisibleAnnotations)loop;
95 }
96 }
97
98 runtimeInvisibleAnnotations = new RuntimeInvisibleAnnotations();
99 runtimeInvisibleAnnotations.next = null;
100 if (attribute != null) {
101
102 lastAttribute.next = runtimeInvisibleAnnotations;
103 } else {
104
105 }
106 return runtimeInvisibleAnnotations;
107 }
108 }