View Javadoc

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                  // should not occur
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         // not found, link a new one to lastAttribute
102         runtimeInvisibleAnnotations = new RuntimeInvisibleAnnotations();
103         runtimeInvisibleAnnotations.next = null;
104         if (attribute != null) {
105             // if arg is null, we are just adding this annotation as the sole attribute
106             lastAttribute.next = runtimeInvisibleAnnotations;
107         } else {
108             //attribute = runtimeInvisibleAnnotations;
109         }
110         return runtimeInvisibleAnnotations;
111     }
112 }