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.javassist;
9
10 import org.codehaus.aspectwerkz.util.Base64;
11 import org.codehaus.aspectwerkz.annotation.instrumentation.AttributeExtractor;
12 import org.codehaus.aspectwerkz.annotation.instrumentation.asm.CustomAttributeHelper;
13 import org.codehaus.aspectwerkz.definition.DescriptorUtil;
14
15 import java.util.ArrayList;
16 import java.util.Arrays;
17 import java.util.Iterator;
18 import java.util.List;
19 import java.lang.reflect.Method;
20
21 import javassist.CtClass;
22 import javassist.CtConstructor;
23 import javassist.CtField;
24 import javassist.CtMethod;
25 import javassist.bytecode.AttributeInfo;
26 import javassist.bytecode.ClassFile;
27 import javassist.bytecode.AnnotationsAttribute;
28 import javassist.bytecode.annotation.StringMemberValue;
29 import javassist.bytecode.annotation.Annotation;
30
31 /***
32 * Javassist implementation of the AttributeExtractor interface. Extracts attributes from the class file on class,
33 * method and field level.
34 *
35 * @author <a href="mailto:jboner@codehaus.org">Jonas Bonér </a>
36 * @author <a href="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
37 */
38 public class JavassistAttributeExtractor implements AttributeExtractor {
39
40 private final static String RUNTIME_INVISIBLE_ANNOTATIONS = "RuntimeInvisibleAnnotations";
41 private final static String CUSTOM_ATTRIBUTE_CLASSNAME = "org.codehaus.aspectwerkz.annotation.instrumentation.asm.CustomAttribute";
42 private final static String VALUE = "value";
43
44 /***
45 * The Javassist class.
46 */
47 private CtClass m_ctClass;
48
49 /***
50 * Open the classfile and parse it in to the Javassist library.
51 *
52 * @param ctClass the class
53 */
54 public void initialize(final CtClass ctClass) {
55 m_ctClass = ctClass;
56 if (!(m_ctClass.isPrimitive() || m_ctClass.isArray())) {
57 m_ctClass.stopPruning(true);
58 m_ctClass.defrost();
59 }
60 }
61
62 /***
63 * Returns the class attributes.
64 *
65 * @return the class attributes
66 */
67 public Object[] getClassAttributes() {
68 if (m_ctClass.isPrimitive() || m_ctClass.isArray()) {
69 return EMPTY_OBJECT_ARRAY;
70 }
71 List attributes = new ArrayList();
72 ClassFile classFile = m_ctClass.getClassFile();
73 List attrs = classFile.getAttributes();
74 for (Iterator it = attrs.iterator(); it.hasNext();) {
75 retrieveCustomAttributes((AttributeInfo) it.next(), attributes);
76 }
77 return attributes.toArray(new Object[attributes.size()]);
78 }
79
80 public Object[] getMethodAttributes(final Method method) {
81 throw new RuntimeException("NA");
82
83 }
84 /***
85 * Return all the attributes associated with a method that have a particular method signature.
86 *
87 * @param methodName The name of the method.
88 * @param methodParamTypes An array of parameter types as given by the reflection api.
89 * @return the method attributes.
90 */
91 public Object[] getMethodAttributes(final String methodName, final String[] methodParamTypes) {
92 if (m_ctClass.isPrimitive() || m_ctClass.isArray()) {
93 return EMPTY_OBJECT_ARRAY;
94 }
95 List attributes = new ArrayList();
96 CtMethod[] methods = m_ctClass.getDeclaredMethods();
97 for (int i = 0; i < methods.length; i++) {
98 CtMethod method = methods[i];
99 if (method.getName().equals(methodName)) {
100 if (Arrays.equals(methodParamTypes, DescriptorUtil.getParameters(methods[i].getSignature()))) {
101 for (Iterator it = method.getMethodInfo().getAttributes().iterator(); it.hasNext();) {
102 retrieveCustomAttributes((AttributeInfo) it.next(), attributes);
103 }
104 }
105 }
106 }
107 return attributes.toArray(new Object[attributes.size()]);
108 }
109
110 /***
111 * Return all the attributes associated with a constructor that have a particular method signature.
112 *
113 * @param constructorParamTypes An array of parameter types as given by the reflection api.
114 * @return the constructor attributes.
115 */
116 public Object[] getConstructorAttributes(final String[] constructorParamTypes) {
117 if (m_ctClass.isPrimitive() || m_ctClass.isArray()) {
118 return EMPTY_OBJECT_ARRAY;
119 }
120 List attributes = new ArrayList();
121 CtConstructor[] constructors = m_ctClass.getDeclaredConstructors();
122 for (int i = 0; i < constructors.length; i++) {
123 CtConstructor constructor = constructors[i];
124 if (Arrays.equals(constructorParamTypes, DescriptorUtil.getParameters(constructors[i].getSignature()))) {
125 for (Iterator it = constructor.getMethodInfo().getAttributes().iterator(); it.hasNext();) {
126 retrieveCustomAttributes((AttributeInfo) it.next(), attributes);
127 }
128 }
129 }
130 return attributes.toArray(new Object[attributes.size()]);
131 }
132
133 /***
134 * Return all the attributes associated with a field.
135 *
136 * @param fieldName The name of the field.
137 * @return the field attributes.
138 */
139 public Object[] getFieldAttributes(final String fieldName) {
140 if (m_ctClass.isPrimitive() || m_ctClass.isArray()) {
141 return EMPTY_OBJECT_ARRAY;
142 }
143 List attributes = new ArrayList();
144 CtField[] fields = m_ctClass.getDeclaredFields();
145 for (int i = 0; i < fields.length; i++) {
146 if (fields[i].getName().equals(fieldName)) {
147 CtField field = fields[i];
148 for (Iterator it = field.getFieldInfo().getAttributes().iterator(); it.hasNext();) {
149 retrieveCustomAttributes((AttributeInfo) it.next(), attributes);
150 }
151 }
152 }
153 return attributes.toArray(new Object[attributes.size()]);
154 }
155
156 /***
157 * Retrieves custom attributes and puts them in a list.
158 *
159 * @param attributeInfo
160 * @param listToPutAttributesIn
161 */
162 private void retrieveCustomAttributes(final AttributeInfo attributeInfo, final List listToPutAttributesIn) {
163 if (attributeInfo.getName().equals(RUNTIME_INVISIBLE_ANNOTATIONS)) {
164
165 if ( !(attributeInfo instanceof AnnotationsAttribute)) {
166 return;
167 }
168 AnnotationsAttribute annotationAttribute = (AnnotationsAttribute)attributeInfo;
169 for (int i = 0; i < annotationAttribute.getAnnotations().length; i++) {
170 Annotation annotation = annotationAttribute.getAnnotations()[i];
171
172
173 if (annotation.getTypeName().equals(CUSTOM_ATTRIBUTE_CLASSNAME)) {
174 String value = ((StringMemberValue)annotation.getMemberValue(VALUE)).getValue();
175 byte[] bytes = Base64.decode(value);
176 listToPutAttributesIn.add(CustomAttributeHelper.extractCustomAnnotation(bytes));
177 }
178 }
179 }
180
181 }
182
183 }