OSDN Git Service

2007-03-02 Andrew Haley <aph@redhat.com>
[pf3gnuchains/gcc-fork.git] / libjava / sun / reflect / annotation / AnnotationInvocationHandler.java
1 /* sun.reflect.annotation.AnnotationInvocationHandler
2    Copyright (C) 2006
3    Free Software Foundation, Inc.
4
5 This file is part of GNU Classpath.
6
7 GNU Classpath is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11  
12 GNU Classpath is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU Classpath; see the file COPYING.  If not, write to the
19 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301 USA.
21
22 Linking this library statically or dynamically with other modules is
23 making a combined work based on this library.  Thus, the terms and
24 conditions of the GNU General Public License cover the whole
25 combination.
26
27 As a special exception, the copyright holders of this library give you
28 permission to link this library with independent modules to produce an
29 executable, regardless of the license terms of these independent
30 modules, and to copy and distribute the resulting executable under
31 terms of your choice, provided that you also meet, for each linked
32 independent module, the terms and conditions of the license of that
33 module.  An independent module is a module which is not derived from
34 or based on this library.  If you modify this library, you may extend
35 this exception to your version of the library, but you are not
36 obligated to do so.  If you do not wish to do so, delete this
37 exception statement from your version. */
38
39 package sun.reflect.annotation;
40
41 import java.io.Serializable;
42 import java.lang.annotation.Annotation;
43 import java.lang.annotation.AnnotationTypeMismatchException;
44 import java.lang.annotation.IncompleteAnnotationException;
45 import java.lang.reflect.InvocationHandler;
46 import java.lang.reflect.InvocationTargetException;
47 import java.lang.reflect.Method;
48 import java.lang.reflect.Proxy;
49 import java.util.Arrays;
50 import java.util.Iterator;
51 import java.util.Map;
52
53 /**
54  * This class exists for serialization compatibility with the JDK.
55  * VMs can choose to implement annotations by constructing proxies
56  * with this invocation handler, but that is not required.
57  * If a different strategy for proxy objects is chosen, they can
58  * have a writeReplace method to substitute a Proxy based on this
59  * invocation handler is used for serialization.
60  */
61 public final class AnnotationInvocationHandler
62   implements InvocationHandler, Serializable
63 {
64   private static final long serialVersionUID = 6182022883658399397L;
65   private final Class type;
66   private final Map memberValues;
67
68   /**
69    * Construct a new invocation handler for an annotation proxy.
70    * Note that the VM is responsible for filling the memberValues map
71    * with the default values of all the annotation members.
72    */
73   public AnnotationInvocationHandler(Class type, Map memberValues)
74   {
75     this.type = type;
76     this.memberValues = memberValues;
77   }
78
79   public static Annotation create(Class type, Map memberValues)
80   {
81     for (Method m : type.getDeclaredMethods())
82       {
83         String name = m.getName();
84         if (! memberValues.containsKey(name))
85           {
86             // FIXME: what to do about exceptions here?
87             memberValues.put(name, m.getDefaultValue());
88           }
89       }
90     AnnotationInvocationHandler handler
91       = new AnnotationInvocationHandler(type, memberValues);
92     return (Annotation) Proxy.newProxyInstance(type.getClassLoader(),
93                                                new Class[] { type },
94                                                handler);
95   }
96
97   /**
98    * Compare an instance of AnnotationInvocationHandler with another object.
99    * Note that the other object does not have to be an
100    * AnnotationInvocationHandler, any implementation of the annotation
101    * interface is allowed to be compared for equality.
102    * Note that this makes the equals method asymmetric, but this behavior
103    * is specified by Annotation.equals and identical to the JDK.
104    *
105    * This method is public for use by other parts of the VM. Some VMs
106    * (can) use different representations of annotations that reuse this
107    * method.
108    */
109   public static boolean equals(Class type, Map memberValues, Object other)
110   {
111     if (type.isInstance(other))
112       {
113         try
114           {
115             Method[] methods = type.getDeclaredMethods();
116             if (methods.length == memberValues.size())
117               {
118                 for (int i = 0; i < methods.length; i++)
119                   {
120                     String key = methods[i].getName();
121                     Object val = methods[i].invoke(other, new Object[0]);
122                     if (! deepEquals(memberValues.get(key), val))
123                       {
124                         return false;
125                       }
126                   }
127                 return true;
128               }
129           }
130         catch (IllegalAccessException _)
131           {
132             // Ignore exception, like the JDK
133           }
134         catch (InvocationTargetException _)
135           {
136             // Ignore exception, like the JDK
137           }
138       }
139     return false;
140   }
141
142   private static boolean deepEquals(Object o1, Object o2)
143   {
144     if (o1 == o2)
145       return true;
146
147     if (o1 == null || o2 == null)
148       return false;
149
150     if (o1 instanceof boolean[] && o2 instanceof boolean[])
151       return Arrays.equals((boolean[]) o1, (boolean[]) o2);
152
153     if (o1 instanceof byte[] && o2 instanceof byte[])
154       return Arrays.equals((byte[]) o1, (byte[]) o2);
155
156     if (o1 instanceof char[] && o2 instanceof char[])
157       return Arrays.equals((char[]) o1, (char[]) o2);
158
159     if (o1 instanceof short[] && o2 instanceof short[])
160       return Arrays.equals((short[]) o1, (short[]) o2);
161
162     if (o1 instanceof int[] && o2 instanceof int[])
163       return Arrays.equals((int[]) o1, (int[]) o2);
164
165     if (o1 instanceof float[] && o2 instanceof float[])
166       return Arrays.equals((float[]) o1, (float[]) o2);
167
168     if (o1 instanceof long[] && o2 instanceof long[])
169       return Arrays.equals((long[]) o1, (long[]) o2);
170
171     if (o1 instanceof double[] && o2 instanceof double[])
172       return Arrays.equals((double[]) o1, (double[]) o2);
173
174     if (o1 instanceof Object[] && o2 instanceof Object[])
175       return Arrays.equals((Object[]) o1, (Object[]) o2);
176
177     return o1.equals(o2);
178   }
179
180   private static int deepHashCode(Object obj)
181   {
182     if (obj instanceof boolean[])
183       return Arrays.hashCode((boolean[]) obj);
184
185     if (obj instanceof byte[])
186       return Arrays.hashCode((byte[]) obj);
187
188     if (obj instanceof char[])
189       return Arrays.hashCode((char[]) obj);
190
191     if (obj instanceof short[])
192       return Arrays.hashCode((short[]) obj);
193
194     if (obj instanceof int[])
195       return Arrays.hashCode((int[]) obj);
196
197     if (obj instanceof float[])
198       return Arrays.hashCode((float[]) obj);
199
200     if (obj instanceof long[])
201       return Arrays.hashCode((long[]) obj);
202
203     if (obj instanceof double[])
204       return Arrays.hashCode((double[]) obj);
205
206     if (obj instanceof Object[])
207       return Arrays.hashCode((Object[]) obj);
208
209     return obj.hashCode();
210   }
211
212   /**
213    * Compute the hashCode for an annotation. Note that the algorithm is
214    * specified by Annotation.hashCode.
215    *
216    * This method is public for use by other parts of the VM. Some VMs
217    * (can) use different representations of annotations that reuse this
218    * method.
219    */
220   public static int hashCode(Class type, Map memberValues)
221   {
222     int h = 0;
223     Iterator iter = memberValues.keySet().iterator();
224     while (iter.hasNext())
225       {
226         Object key = iter.next();
227         Object val = memberValues.get(key);
228         h += deepHashCode(val) ^ 127 * key.hashCode();
229       }
230     return h;
231   }
232
233   private static String deepToString(Object obj)
234   {
235     if (obj instanceof boolean[])
236       return Arrays.toString((boolean[]) obj);
237
238     if (obj instanceof byte[])
239       return Arrays.toString((byte[]) obj);
240
241     if (obj instanceof char[])
242       return Arrays.toString((char[]) obj);
243
244     if (obj instanceof short[])
245       return Arrays.toString((short[]) obj);
246
247     if (obj instanceof int[])
248       return Arrays.toString((int[]) obj);
249
250     if (obj instanceof float[])
251       return Arrays.toString((float[]) obj);
252
253     if (obj instanceof long[])
254       return Arrays.toString((long[]) obj);
255
256     if (obj instanceof double[])
257       return Arrays.toString((double[]) obj);
258
259     if (obj instanceof Object[])
260       return Arrays.toString((Object[]) obj);
261
262     return obj.toString();
263   }
264
265   /**
266    * This method is public for use by other parts of the VM. Some VMs
267    * (can) use different representations of annotations that reuse this
268    * method.
269    */
270   public static String toString(Class type, Map memberValues)
271   {
272     StringBuffer sb = new StringBuffer();
273     sb.append('@').append(type.getName()).append('(');
274     String sep = "";
275     Iterator iter = memberValues.keySet().iterator();
276     while (iter.hasNext())
277       {
278         Object key = iter.next();
279         Object val = memberValues.get(key);
280         sb.append(sep).append(key).append('=').append(deepToString(val));
281         sep = ", ";
282       }
283     sb.append(')');
284     return sb.toString();
285   }
286
287   private static Class getBoxedReturnType(Method method)
288   {
289     Class returnType = method.getReturnType();
290
291     if (returnType == boolean.class)
292       return Boolean.class;
293
294     if (returnType == byte.class)
295       return Byte.class;
296
297     if (returnType == char.class)
298       return Character.class;
299
300     if (returnType == short.class)
301       return Short.class;
302
303     if (returnType == int.class)
304       return Integer.class;
305
306     if (returnType == float.class)
307       return Float.class;
308
309     if (returnType == long.class)
310       return Long.class;
311
312     if (returnType == double.class)
313       return Double.class;
314
315     return returnType;
316   }
317
318   private Object arrayClone(Object obj)
319   {
320     if (obj instanceof boolean[])
321       return ((boolean[]) obj).clone();
322
323     if (obj instanceof byte[])
324       return ((byte[]) obj).clone();
325
326     if (obj instanceof char[])
327       return ((char[]) obj).clone();
328
329     if (obj instanceof short[])
330       return ((short[]) obj).clone();
331
332     if (obj instanceof int[])
333       return ((int[]) obj).clone();
334
335     if (obj instanceof float[])
336       return ((float[]) obj).clone();
337
338     if (obj instanceof long[])
339       return ((long[]) obj).clone();
340
341     if (obj instanceof double[])
342       return ((double[]) obj).clone();
343
344     if (obj instanceof Object[])
345       return ((Object[]) obj).clone();
346
347     return obj;
348   }
349
350   public Object invoke(Object proxy, Method method, Object[] args)
351     throws Throwable
352   {
353     String methodName = method.getName().intern();
354     if (args == null || args.length == 0)
355       {
356         if (methodName == "toString")
357           {
358             return toString(type, memberValues);
359           }
360         else if (methodName == "hashCode")
361           {
362             return Integer.valueOf(hashCode(type, memberValues));
363           }
364         else if (methodName == "annotationType")
365           {
366             return type;
367           }
368         else
369           {
370             Object val = memberValues.get(methodName);
371             if (val == null)
372               {
373                 throw new IncompleteAnnotationException(type, methodName);
374               }
375             if (! getBoxedReturnType(method).isInstance(val))
376               {
377                 throw new AnnotationTypeMismatchException(method,
378                                                           val.getClass().getName());
379               }
380             if (val.getClass().isArray())
381               {
382                 val = arrayClone(val);
383               }
384             return val;
385           }
386       }
387     else if (args.length == 1)
388       {
389         if (methodName == "equals")
390           {
391             return Boolean.valueOf(equals(type, memberValues, args[0]));
392           }
393       }
394     throw new InternalError("Invalid annotation proxy");
395   }
396 }