1 /* sun.reflect.annotation.AnnotationInvocationHandler
3 Free Software Foundation, Inc.
5 This file is part of GNU Classpath.
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)
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.
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
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
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. */
39 package sun.reflect.annotation;
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;
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.
61 public final class AnnotationInvocationHandler
62 implements InvocationHandler, Serializable
64 private static final long serialVersionUID = 6182022883658399397L;
65 private final Class type;
66 private final Map memberValues;
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.
73 public AnnotationInvocationHandler(Class type, Map memberValues)
76 this.memberValues = memberValues;
79 public static Annotation create(Class type, Map memberValues)
81 for (Method m : type.getDeclaredMethods())
83 String name = m.getName();
84 if (! memberValues.containsKey(name))
86 // FIXME: what to do about exceptions here?
87 memberValues.put(name, m.getDefaultValue());
90 AnnotationInvocationHandler handler
91 = new AnnotationInvocationHandler(type, memberValues);
92 return (Annotation) Proxy.newProxyInstance(type.getClassLoader(),
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.
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
109 public static boolean equals(Class type, Map memberValues, Object other)
111 if (type.isInstance(other))
115 Method[] methods = type.getDeclaredMethods();
116 if (methods.length == memberValues.size())
118 for (int i = 0; i < methods.length; i++)
120 String key = methods[i].getName();
121 Object val = methods[i].invoke(other, new Object[0]);
122 if (! deepEquals(memberValues.get(key), val))
130 catch (IllegalAccessException _)
132 // Ignore exception, like the JDK
134 catch (InvocationTargetException _)
136 // Ignore exception, like the JDK
142 private static boolean deepEquals(Object o1, Object o2)
147 if (o1 == null || o2 == null)
150 if (o1 instanceof boolean[] && o2 instanceof boolean[])
151 return Arrays.equals((boolean[]) o1, (boolean[]) o2);
153 if (o1 instanceof byte[] && o2 instanceof byte[])
154 return Arrays.equals((byte[]) o1, (byte[]) o2);
156 if (o1 instanceof char[] && o2 instanceof char[])
157 return Arrays.equals((char[]) o1, (char[]) o2);
159 if (o1 instanceof short[] && o2 instanceof short[])
160 return Arrays.equals((short[]) o1, (short[]) o2);
162 if (o1 instanceof int[] && o2 instanceof int[])
163 return Arrays.equals((int[]) o1, (int[]) o2);
165 if (o1 instanceof float[] && o2 instanceof float[])
166 return Arrays.equals((float[]) o1, (float[]) o2);
168 if (o1 instanceof long[] && o2 instanceof long[])
169 return Arrays.equals((long[]) o1, (long[]) o2);
171 if (o1 instanceof double[] && o2 instanceof double[])
172 return Arrays.equals((double[]) o1, (double[]) o2);
174 if (o1 instanceof Object[] && o2 instanceof Object[])
175 return Arrays.equals((Object[]) o1, (Object[]) o2);
177 return o1.equals(o2);
180 private static int deepHashCode(Object obj)
182 if (obj instanceof boolean[])
183 return Arrays.hashCode((boolean[]) obj);
185 if (obj instanceof byte[])
186 return Arrays.hashCode((byte[]) obj);
188 if (obj instanceof char[])
189 return Arrays.hashCode((char[]) obj);
191 if (obj instanceof short[])
192 return Arrays.hashCode((short[]) obj);
194 if (obj instanceof int[])
195 return Arrays.hashCode((int[]) obj);
197 if (obj instanceof float[])
198 return Arrays.hashCode((float[]) obj);
200 if (obj instanceof long[])
201 return Arrays.hashCode((long[]) obj);
203 if (obj instanceof double[])
204 return Arrays.hashCode((double[]) obj);
206 if (obj instanceof Object[])
207 return Arrays.hashCode((Object[]) obj);
209 return obj.hashCode();
213 * Compute the hashCode for an annotation. Note that the algorithm is
214 * specified by Annotation.hashCode.
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
220 public static int hashCode(Class type, Map memberValues)
223 Iterator iter = memberValues.keySet().iterator();
224 while (iter.hasNext())
226 Object key = iter.next();
227 Object val = memberValues.get(key);
228 h += deepHashCode(val) ^ 127 * key.hashCode();
233 private static String deepToString(Object obj)
235 if (obj instanceof boolean[])
236 return Arrays.toString((boolean[]) obj);
238 if (obj instanceof byte[])
239 return Arrays.toString((byte[]) obj);
241 if (obj instanceof char[])
242 return Arrays.toString((char[]) obj);
244 if (obj instanceof short[])
245 return Arrays.toString((short[]) obj);
247 if (obj instanceof int[])
248 return Arrays.toString((int[]) obj);
250 if (obj instanceof float[])
251 return Arrays.toString((float[]) obj);
253 if (obj instanceof long[])
254 return Arrays.toString((long[]) obj);
256 if (obj instanceof double[])
257 return Arrays.toString((double[]) obj);
259 if (obj instanceof Object[])
260 return Arrays.toString((Object[]) obj);
262 return obj.toString();
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
270 public static String toString(Class type, Map memberValues)
272 StringBuffer sb = new StringBuffer();
273 sb.append('@').append(type.getName()).append('(');
275 Iterator iter = memberValues.keySet().iterator();
276 while (iter.hasNext())
278 Object key = iter.next();
279 Object val = memberValues.get(key);
280 sb.append(sep).append(key).append('=').append(deepToString(val));
284 return sb.toString();
287 private static Class getBoxedReturnType(Method method)
289 Class returnType = method.getReturnType();
291 if (returnType == boolean.class)
292 return Boolean.class;
294 if (returnType == byte.class)
297 if (returnType == char.class)
298 return Character.class;
300 if (returnType == short.class)
303 if (returnType == int.class)
304 return Integer.class;
306 if (returnType == float.class)
309 if (returnType == long.class)
312 if (returnType == double.class)
318 private Object arrayClone(Object obj)
320 if (obj instanceof boolean[])
321 return ((boolean[]) obj).clone();
323 if (obj instanceof byte[])
324 return ((byte[]) obj).clone();
326 if (obj instanceof char[])
327 return ((char[]) obj).clone();
329 if (obj instanceof short[])
330 return ((short[]) obj).clone();
332 if (obj instanceof int[])
333 return ((int[]) obj).clone();
335 if (obj instanceof float[])
336 return ((float[]) obj).clone();
338 if (obj instanceof long[])
339 return ((long[]) obj).clone();
341 if (obj instanceof double[])
342 return ((double[]) obj).clone();
344 if (obj instanceof Object[])
345 return ((Object[]) obj).clone();
350 public Object invoke(Object proxy, Method method, Object[] args)
353 String methodName = method.getName().intern();
354 if (args == null || args.length == 0)
356 if (methodName == "toString")
358 return toString(type, memberValues);
360 else if (methodName == "hashCode")
362 return Integer.valueOf(hashCode(type, memberValues));
364 else if (methodName == "annotationType")
370 Object val = memberValues.get(methodName);
373 throw new IncompleteAnnotationException(type, methodName);
375 if (! getBoxedReturnType(method).isInstance(val))
377 throw new AnnotationTypeMismatchException(method,
378 val.getClass().getName());
380 if (val.getClass().isArray())
382 val = arrayClone(val);
387 else if (args.length == 1)
389 if (methodName == "equals")
391 return Boolean.valueOf(equals(type, memberValues, args[0]));
394 throw new InternalError("Invalid annotation proxy");