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