KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > tc > backport175 > proxy > JavaDocAnnotationInvocationHander


1 /*******************************************************************************************
2  * Copyright (c) Jonas Bonér, Alexandre Vasseur. All rights reserved. *
3  * http://backport175.codehaus.org *
4  * --------------------------------------------------------------------------------------- *
5  * The software in this package is published under the terms of Apache License Version 2.0 *
6  * a copy of which has been included with this distribution in the license.txt file. *
7  *******************************************************************************************/

8 package com.tc.backport175.proxy;
9
10 import com.tc.backport175.bytecode.AnnotationElement;
11 import com.tc.backport175.bytecode.AnnotationReader;
12
13 import com.tc.asm.Type;
14
15 import java.lang.reflect.InvocationHandler JavaDoc;
16 import java.lang.reflect.Method JavaDoc;
17 import java.lang.reflect.Array JavaDoc;
18 import java.lang.reflect.Field JavaDoc;
19 import java.io.Serializable JavaDoc;
20 import java.util.Iterator JavaDoc;
21 import java.util.List JavaDoc;
22 import java.util.ArrayList JavaDoc;
23
24 /**
25  * Implements a strongly typed reader handler for JavaDoc annotations.
26  *
27  * @author <a HREF="mailto:jboner@codehaus.org">Jonas Bonér</a>
28  * @author <a HREF="mailto:alex AT gnilux DOT com">Alexandre Vasseur</a>
29  */

30 public class JavaDocAnnotationInvocationHander implements InvocationHandler JavaDoc, Serializable JavaDoc {
31     static final long serialVersionUID = 1584167345753299421L;
32
33     private static final String JavaDoc TO_STRING_METHOD_NAME = "toString";
34     private static final String JavaDoc ANNOTATION_TYPE_METHOD_NAME = "annotationType";
35
36     private final Class JavaDoc m_annotationInterface;
37     private final AnnotationElement.Annotation m_annotation;
38     private final String JavaDoc m_annotationName;
39
40     /**
41      * The annotated class classloader. Strong ref is ok since we use a proxy handler
42      * and that one will be referenced by this classloader precisely
43      */

44     private final ClassLoader JavaDoc m_annotatedClassClassLoader;
45
46     private ClassLoader JavaDoc getAnnotatedClassClassLoader() {
47         return m_annotatedClassClassLoader;
48     }
49
50     /**
51      * Constructor that will trigger the parsing if required
52      *
53      * @param annotationInterface
54      * @param annotation
55      * @param annotatedClassClassLoader classloader of the annotated class from which we can safely load all values
56      */

57     public JavaDocAnnotationInvocationHander(
58             final Class JavaDoc annotationInterface,
59             final AnnotationElement.Annotation annotation,
60             final ClassLoader JavaDoc annotatedClassClassLoader) {
61         m_annotationInterface = annotationInterface;
62         m_annotation = annotation;
63         m_annotationName = annotationInterface.getName().replace('/', '.');
64         m_annotatedClassClassLoader = annotatedClassClassLoader!=null?annotatedClassClassLoader:ClassLoader.getSystemClassLoader();
65     }
66
67     /**
68      * The proxy invoke method, dispatches to the target method being invoked.
69      *
70      * @param proxy
71      * @param method
72      * @param args
73      * @return
74      * @throws Throwable
75      */

76     public Object JavaDoc invoke(final Object JavaDoc proxy, final Method JavaDoc method, final Object JavaDoc[] args) throws Throwable JavaDoc {
77         final String JavaDoc methodName = method.getName();
78         if (methodName.equals(ANNOTATION_TYPE_METHOD_NAME)) {
79             return m_annotationInterface;
80         } else if (methodName.equals(TO_STRING_METHOD_NAME)) {
81             return invokeToString();
82         } else {
83             return invokeAnnotationValue(method);
84         }
85     }
86
87     /**
88      * Handle invocation of an annotation value method.
89      *
90      * @param method
91      * @return
92      */

93     private Object JavaDoc invokeAnnotationValue(final Method JavaDoc method) {
94         Object JavaDoc returnValue = null;
95         for (Iterator JavaDoc it = m_annotation.getElements().iterator(); it.hasNext();) {
96             AnnotationElement.NamedValue namedValue = (AnnotationElement.NamedValue)it.next();
97             if (namedValue.getName().equals(method.getName())) {
98                 returnValue = resolveValue(namedValue, method.getReturnType());
99                 break;
100             }
101         }
102         return returnValue;
103     }
104
105     /**
106      * Handles invocation of the <code>toString</code> method.
107      *
108      * @return the string representation for the annotation
109      */

110     private Object JavaDoc invokeToString() {
111         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
112         sb.append('@');
113         sb.append(m_annotationName);
114         sb.append('(');
115         sb.append(m_annotation.toString());
116         sb.append(')');
117         return sb.toString();
118     }
119
120     /**
121      * Returns the resolved value for the annotation element.
122      *
123      * @param namedValue
124      * @param valueType
125      * @return
126      */

127     private Object JavaDoc resolveValue(final AnnotationElement.NamedValue namedValue, final Class JavaDoc valueType) {
128         if (namedValue.isResolved()) {
129             return namedValue.getResolvedValue();
130         }
131         AnnotationElement.Type type = namedValue.getType();
132         final Object JavaDoc value;
133         if (type.equals(AnnotationElement.Type.ANNOTATION)) {
134             AnnotationElement.Annotation annotation = (AnnotationElement.Annotation)namedValue.getValue();
135             value = ProxyFactory.newAnnotationProxy(annotation, getAnnotatedClassClassLoader());
136
137         } else if (type.equals(AnnotationElement.Type.ARRAY)) {
138             value = resolveArray(namedValue, valueType);
139
140         } else if (type.equals(AnnotationElement.Type.ENUM)) {
141             value = resolveEnum(namedValue);
142
143         } else if (type.equals(AnnotationElement.Type.TYPE)) {
144             value = resolveType(namedValue);
145
146         } else {
147             value = namedValue.getValue();
148         }
149         namedValue.setResolvedValue(value);
150         return value;
151     }
152
153     /**
154      * Returns the class of an unresolved type.
155      *
156      * @param namedValue
157      * @return
158      */

159     private Object JavaDoc resolveType(final AnnotationElement.NamedValue namedValue) {
160         final Object JavaDoc value = namedValue.getValue();
161         if (value instanceof Type) {
162             // type
163
final Type type = (Type)value;
164             final Class JavaDoc resolvedType;
165             try {
166                 if (type.getClassName().endsWith("[]")) {
167                     //if (type.getDimensions() > 0) { // Note: Bugs in ASM prevents me from using this check, first: if type is primitive -> NPE, second: dimension is wrong for non-array types (1)
168
int dimensions = type.getDimensions();
169                     Type elementType = type.getElementType();
170                     Class JavaDoc componentType = resolveType(elementType);
171                     resolvedType = Array.newInstance(componentType, new int[dimensions]).getClass();
172                 } else {
173                     resolvedType = resolveType(type);
174                 }
175             } catch (ClassNotFoundException JavaDoc cnfe) {
176                 throw new ResolveAnnotationException(
177                         "class [" + type.getClassName() + "] defined in annotation can not be found in class loader [" +
178                         m_annotatedClassClassLoader + "]", cnfe
179                 );
180             }
181             return resolvedType;
182         } else {
183             // primitive value
184
return value;
185         }
186     }
187
188     /**
189      * Resolves a type.
190      *
191      * @param type
192      * @return
193      * @throws ClassNotFoundException
194      */

195     private Class JavaDoc resolveType(final Type type) throws ClassNotFoundException JavaDoc {
196         Class JavaDoc resolvedType;
197         if (Type.LONG_TYPE.equals(type)) {
198             resolvedType = long.class;
199         } else if (Type.INT_TYPE.equals(type)) {
200             resolvedType = int.class;
201         } else if (Type.SHORT_TYPE.equals(type)) {
202             resolvedType = short.class;
203         } else if (Type.DOUBLE_TYPE.equals(type)) {
204             resolvedType = double.class;
205         } else if (Type.FLOAT_TYPE.equals(type)) {
206             resolvedType = float.class;
207         } else if (Type.BOOLEAN_TYPE.equals(type)) {
208             resolvedType = boolean.class;
209         } else if (Type.BYTE_TYPE.equals(type)) {
210             resolvedType = byte.class;
211         } else if (Type.CHAR_TYPE.equals(type)) {
212             resolvedType = char.class;
213         } else {
214             resolvedType = Class.forName(type.getClassName(), false, getAnnotatedClassClassLoader());
215         }
216         return resolvedType;
217     }
218
219     /**
220      * Retuns the value of an enum (static field reference).
221      *
222      * @param namedValue
223      * @return
224      */

225     private Object JavaDoc resolveEnum(final AnnotationElement.NamedValue namedValue) {
226         AnnotationElement.Enum enumElement = (AnnotationElement.Enum)namedValue.getValue();
227         String JavaDoc className = AnnotationReader.toJavaName(enumElement.getDesc());
228         String JavaDoc value = enumElement.getValue();
229
230         try {
231             Class JavaDoc clazz = Class.forName(className, false, getAnnotatedClassClassLoader());
232             Field JavaDoc field = clazz.getDeclaredField(value);
233             try {
234                 return field.get(null);
235             } catch (IllegalAccessException JavaDoc e) {
236                 throw new ResolveAnnotationException(
237                         "can not access static reference field due to: " + e.toString(), e
238                 );
239             }
240         } catch (Exception JavaDoc e) {
241             throw new ResolveAnnotationException(
242                     "could not retrieve static reference to field (enum) [" + className + "." +
243                     namedValue.getName() + "] due to: " + e.toString(), e
244             );
245         }
246     }
247
248     /**
249      * Resolves the array type and returns an array instance of the correct type (including primitive types).
250      *
251      * @param namedValue
252      * @param valueType
253      * @return
254      */

255     private Object JavaDoc resolveArray(final AnnotationElement.NamedValue namedValue, final Class JavaDoc valueType) {
256         if (!valueType.isArray()) {
257             throw new IllegalArgumentException JavaDoc(
258                     "annotation interface method [" + namedValue.getName() + "] in interface [" + m_annotationName +
259                     "] needs to return an ARRAY type"
260             );
261         }
262         AnnotationElement.Array array = (AnnotationElement.Array)namedValue.getValue();
263         Class JavaDoc componentType = valueType.getComponentType();
264
265         List JavaDoc arrayElements = array.getElements();
266         List JavaDoc elementList = new ArrayList JavaDoc();
267         for (Iterator JavaDoc it2 = arrayElements.iterator(); it2.hasNext();) {
268             AnnotationElement.NamedValue arrayValue = (AnnotationElement.NamedValue)it2.next();
269
270             // recursive call to resolveValue(..)
271
elementList.add(resolveValue(arrayValue, componentType));
272         }
273
274         if (componentType.isPrimitive()) {
275             if (componentType.equals(int.class)) {
276                 int[] arrayInstance = (int[])Array.newInstance(componentType, arrayElements.size());
277                 int i = 0;
278                 for (Iterator JavaDoc it = elementList.iterator(); it.hasNext();) {
279                     Integer JavaDoc primitive = (Integer JavaDoc)it.next();
280                     arrayInstance[i++] = primitive.intValue();
281                 }
282                 return arrayInstance;
283             } else if (componentType.equals(long.class)) {
284                 long[] arrayInstance = (long[])Array.newInstance(componentType, arrayElements.size());
285                 int i = 0;
286                 for (Iterator JavaDoc it = elementList.iterator(); it.hasNext();) {
287                     Long JavaDoc primitive = (Long JavaDoc)it.next();
288                     arrayInstance[i++] = primitive.longValue();
289                 }
290                 return arrayInstance;
291             } else if (componentType.equals(short.class)) {
292                 short[] arrayInstance = (short[])Array.newInstance(componentType, arrayElements.size());
293                 int i = 0;
294                 for (Iterator JavaDoc it = elementList.iterator(); it.hasNext();) {
295                     Short JavaDoc primitive = (Short JavaDoc)it.next();
296                     arrayInstance[i++] = primitive.shortValue();
297                 }
298                 return arrayInstance;
299             } else if (componentType.equals(float.class)) {
300                 float[] arrayInstance = (float[])Array.newInstance(componentType, arrayElements.size());
301                 int i = 0;
302                 for (Iterator JavaDoc it = elementList.iterator(); it.hasNext();) {
303                     Float JavaDoc primitive = (Float JavaDoc)it.next();
304                     arrayInstance[i++] = primitive.floatValue();
305                 }
306                 return arrayInstance;
307             } else if (componentType.equals(double.class)) {
308                 double[] arrayInstance = (double[])Array.newInstance(componentType, arrayElements.size());
309                 int i = 0;
310                 for (Iterator JavaDoc it = elementList.iterator(); it.hasNext();) {
311                     Double JavaDoc primitive = (Double JavaDoc)it.next();
312                     arrayInstance[i++] = primitive.doubleValue();
313                 }
314                 return arrayInstance;
315             } else if (componentType.equals(char.class)) {
316                 char[] arrayInstance = (char[])Array.newInstance(componentType, arrayElements.size());
317                 int i = 0;
318                 for (Iterator JavaDoc it = elementList.iterator(); it.hasNext();) {
319                     Character JavaDoc primitive = (Character JavaDoc)it.next();
320                     arrayInstance[i++] = primitive.charValue();
321                 }
322                 return arrayInstance;
323             } else if (componentType.equals(boolean.class)) {
324                 boolean[] arrayInstance = (boolean[])Array.newInstance(componentType, arrayElements.size());
325                 int i = 0;
326                 for (Iterator JavaDoc it = elementList.iterator(); it.hasNext();) {
327                     Boolean JavaDoc primitive = (Boolean JavaDoc)it.next();
328                     arrayInstance[i++] = primitive.booleanValue();
329                 }
330                 return arrayInstance;
331             } else if (componentType.equals(byte.class)) {
332                 byte[] arrayInstance = (byte[])Array.newInstance(componentType, arrayElements.size());
333                 int i = 0;
334                 for (Iterator JavaDoc it = elementList.iterator(); it.hasNext();) {
335                     Byte JavaDoc primitive = (Byte JavaDoc)it.next();
336                     arrayInstance[i++] = primitive.byteValue();
337                 }
338                 return arrayInstance;
339             }
340         } else {
341             Object JavaDoc[] arrayInstance = (Object JavaDoc[])Array.newInstance(componentType, arrayElements.size());
342             int i = 0;
343             for (Iterator JavaDoc it = elementList.iterator(); it.hasNext();) {
344                 Object JavaDoc element = it.next();
345                 arrayInstance[i++] = element;
346             }
347             return arrayInstance;
348         }
349         return null;
350     }
351
352 }
353
354
Popular Tags