001: /**************************************************************************************
002: * Copyright (c) Jonas Bon?r, Alexandre Vasseur. All rights reserved. *
003: * http://aspectwerkz.codehaus.org *
004: * ---------------------------------------------------------------------------------- *
005: * The software in this package is published under the terms of the LGPL license *
006: * a copy of which has been included with this distribution in the license.txt file. *
007: **************************************************************************************/package org.codehaus.aspectwerkz.annotation.instrumentation.asm;
008:
009: import org.objectweb.asm.attrs.Annotation;
010: import org.objectweb.asm.attrs.RuntimeInvisibleAnnotations;
011: import org.objectweb.asm.Attribute;
012: import org.codehaus.aspectwerkz.util.Base64;
013: import org.codehaus.aspectwerkz.util.UnbrokenObjectInputStream;
014: import org.codehaus.aspectwerkz.annotation.AnnotationInfo;
015: import org.codehaus.aspectwerkz.exception.WrappedRuntimeException;
016:
017: import java.io.ByteArrayInputStream;
018:
019: /**
020: * Helper class to wrap a custom annotation proxy (1.3/1.4 javadoc annotation) in a RuntimeInvisibleAnnotations.
021: * <br/>
022: * The proxy is wrapped in a AnnotationInfo object which is serialized
023: * and base64 encoded (ASM issue on array types in RIV).
024: *
025: * @author <a href="mailto:alex@gnilux.com">Alexandre Vasseur</a>
026: */
027: public class CustomAttributeHelper {
028:
029: /**
030: * Annotation parameter - as if it was a single value Tiger annotation
031: */
032: private final static String VALUE = "value";
033:
034: /**
035: * Extract the AnnotationInfo from the bytecode Annotation representation.
036: *
037: * @param annotation must be a valid RIV, of type CustomAttribute.TYPE
038: * @return
039: */
040: public static AnnotationInfo extractCustomAnnotation(
041: final Annotation annotation) {
042: byte[] bytes = Base64
043: .decode((String) ((Object[]) annotation.elementValues
044: .get(0))[1]);
045: return extractCustomAnnotation(bytes);
046: }
047:
048: /**
049: * Extract the AnnotationInfo from the base64 encoded serialized version.
050: *
051: * @param bytes
052: * @return
053: */
054: private static AnnotationInfo extractCustomAnnotation(
055: final byte[] bytes) {
056: try {
057: Object userAnnotation = new UnbrokenObjectInputStream(
058: new ByteArrayInputStream(bytes)).readObject();
059: if (userAnnotation instanceof AnnotationInfo) {
060: return (AnnotationInfo) userAnnotation;
061: } else {
062: // should not occur
063: throw new RuntimeException(
064: "Custom annotation is not wrapped in AnnotationInfo: "
065: + userAnnotation.getClass().getName()
066: + " ["
067: + AnnotationInfo.class.getClassLoader()
068: .toString()
069: + " / "
070: + userAnnotation.getClass()
071: .getClassLoader().toString()
072: + " / "
073: + Thread.currentThread()
074: .getContextClassLoader());
075: }
076: } catch (Exception e) {
077: throw new WrappedRuntimeException(e);
078: }
079: }
080:
081: /**
082: * Create an Annotation bytecode representation from the serialized version of the custom annotation proxy
083: *
084: * @param bytes
085: * @return
086: */
087: public static Annotation createCustomAnnotation(final byte[] bytes) {
088: Annotation annotation = new Annotation();
089: annotation.type = CustomAttribute.TYPE;
090: annotation.add(VALUE, Base64.encodeBytes(bytes));
091: return annotation;
092: }
093:
094: /**
095: * Helper method to find the first RuntimeInvisibleAnnotations attribute in an Attribute chain.
096: * <br/>If no such RIV exists, a new one is created (empty) and added last in the chain.
097: * <br/>If the chain is null, a new sole RIV (empty) is created
098: *
099: * @param attribute
100: * @return the RuntimeInvisibleAnnotations to add Annotation to
101: */
102: public static RuntimeInvisibleAnnotations linkRuntimeInvisibleAnnotations(
103: final Attribute attribute) {
104: RuntimeInvisibleAnnotations runtimeInvisibleAnnotations = null;
105: Attribute lastAttribute = attribute;
106: for (Attribute loop = attribute; loop != null; loop = loop.next) {
107: lastAttribute = loop;
108: if (loop instanceof RuntimeInvisibleAnnotations) {
109: return runtimeInvisibleAnnotations = (RuntimeInvisibleAnnotations) loop;
110: }
111: }
112: // not found, link a new one to lastAttribute
113: runtimeInvisibleAnnotations = new RuntimeInvisibleAnnotations();
114: runtimeInvisibleAnnotations.next = null;
115: if (attribute != null) {
116: // if arg is null, we are just adding this annotation as the sole attribute
117: lastAttribute.next = runtimeInvisibleAnnotations;
118: } else {
119: //attribute = runtimeInvisibleAnnotations;
120: }
121: return runtimeInvisibleAnnotations;
122: }
123: }
|