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 }