23 * have any questions.
24 */
25
26 package sun.reflect.annotation;
27
28 import java.lang.annotation.*;
29 import java.lang.reflect.*;
30 import java.io.Serializable;
31 import java.util.*;
32 import java.lang.annotation.*;
33 import java.security.AccessController;
34 import java.security.PrivilegedAction;
35
36 /**
37 * InvocationHandler for dynamic proxy implementation of Annotation.
38 *
39 * @author Josh Bloch
40 * @since 1.5
41 */
42 class AnnotationInvocationHandler implements InvocationHandler, Serializable {
43 private final Class type;
44 private final Map<String, Object> memberValues;
45
46 AnnotationInvocationHandler(Class type, Map<String, Object> memberValues) {
47 this.type = type;
48 this.memberValues = memberValues;
49 }
50
51 public Object invoke(Object proxy, Method method, Object[] args) {
52 String member = method.getName();
53 Class[] paramTypes = method.getParameterTypes();
54
55 // Handle Object and Annotation methods
56 if (member.equals("equals") && paramTypes.length == 1 &&
57 paramTypes[0] == Object.class)
58 return equalsImpl(args[0]);
59 assert paramTypes.length == 0;
60 if (member.equals("toString"))
61 return toStringImpl();
62 if (member.equals("hashCode"))
63 return hashCodeImpl();
64 if (member.equals("annotationType"))
65 return type;
66
67 // Handle annotation member accessors
68 Object result = memberValues.get(member);
69
70 if (result == null)
71 throw new IncompleteAnnotationException(type, member);
72
73 if (result instanceof ExceptionProxy)
74 throw ((ExceptionProxy) result).generateException();
75
76 if (result.getClass().isArray() && Array.getLength(result) != 0)
77 result = cloneArray(result);
78
79 return result;
80 }
81
82 /**
83 * This method, which clones its array argument, would not be necessary
84 * if Cloneable had a public clone method.
85 */
86 private Object cloneArray(Object array) {
87 Class type = array.getClass();
88
89 if (type == byte[].class) {
90 byte[] byteArray = (byte[])array;
91 return byteArray.clone();
92 }
93 if (type == char[].class) {
94 char[] charArray = (char[])array;
95 return charArray.clone();
96 }
97 if (type == double[].class) {
98 double[] doubleArray = (double[])array;
99 return doubleArray.clone();
100 }
101 if (type == float[].class) {
102 float[] floatArray = (float[])array;
103 return floatArray.clone();
104 }
105 if (type == int[].class) {
106 int[] intArray = (int[])array;
107 return intArray.clone();
134 result.append('(');
135 boolean firstMember = true;
136 for (Map.Entry<String, Object> e : memberValues.entrySet()) {
137 if (firstMember)
138 firstMember = false;
139 else
140 result.append(", ");
141
142 result.append(e.getKey());
143 result.append('=');
144 result.append(memberValueToString(e.getValue()));
145 }
146 result.append(')');
147 return result.toString();
148 }
149
150 /**
151 * Translates a member value (in "dynamic proxy return form") into a string
152 */
153 private static String memberValueToString(Object value) {
154 Class type = value.getClass();
155 if (!type.isArray()) // primitive, string, class, enum const,
156 // or annotation
157 return value.toString();
158
159 if (type == byte[].class)
160 return Arrays.toString((byte[]) value);
161 if (type == char[].class)
162 return Arrays.toString((char[]) value);
163 if (type == double[].class)
164 return Arrays.toString((double[]) value);
165 if (type == float[].class)
166 return Arrays.toString((float[]) value);
167 if (type == int[].class)
168 return Arrays.toString((int[]) value);
169 if (type == long[].class)
170 return Arrays.toString((long[]) value);
171 if (type == short[].class)
172 return Arrays.toString((short[]) value);
173 if (type == boolean[].class)
174 return Arrays.toString((boolean[]) value);
212 * Returns null otherwise.
213 */
214 private AnnotationInvocationHandler asOneOfUs(Object o) {
215 if (Proxy.isProxyClass(o.getClass())) {
216 InvocationHandler handler = Proxy.getInvocationHandler(o);
217 if (handler instanceof AnnotationInvocationHandler)
218 return (AnnotationInvocationHandler) handler;
219 }
220 return null;
221 }
222
223 /**
224 * Returns true iff the two member values in "dynamic proxy return form"
225 * are equal using the appropriate equality function depending on the
226 * member type. The two values will be of the same type unless one of
227 * the containing annotations is ill-formed. If one of the containing
228 * annotations is ill-formed, this method will return false unless the
229 * two members are identical object references.
230 */
231 private static boolean memberValueEquals(Object v1, Object v2) {
232 Class type = v1.getClass();
233
234 // Check for primitive, string, class, enum const, annotation,
235 // or ExceptionProxy
236 if (!type.isArray())
237 return v1.equals(v2);
238
239 // Check for array of string, class, enum const, annotation,
240 // or ExceptionProxy
241 if (v1 instanceof Object[] && v2 instanceof Object[])
242 return Arrays.equals((Object[]) v1, (Object[]) v2);
243
244 // Check for ill formed annotation(s)
245 if (v2.getClass() != type)
246 return false;
247
248 // Deal with array of primitives
249 if (type == byte[].class)
250 return Arrays.equals((byte[]) v1, (byte[]) v2);
251 if (type == char[].class)
252 return Arrays.equals((char[]) v1, (char[]) v2);
284 return memberMethods;
285 }
286 private transient volatile Method[] memberMethods = null;
287
288 /**
289 * Implementation of dynamicProxy.hashCode()
290 */
291 private int hashCodeImpl() {
292 int result = 0;
293 for (Map.Entry<String, Object> e : memberValues.entrySet()) {
294 result += (127 * e.getKey().hashCode()) ^
295 memberValueHashCode(e.getValue());
296 }
297 return result;
298 }
299
300 /**
301 * Computes hashCode of a member value (in "dynamic proxy return form")
302 */
303 private static int memberValueHashCode(Object value) {
304 Class type = value.getClass();
305 if (!type.isArray()) // primitive, string, class, enum const,
306 // or annotation
307 return value.hashCode();
308
309 if (type == byte[].class)
310 return Arrays.hashCode((byte[]) value);
311 if (type == char[].class)
312 return Arrays.hashCode((char[]) value);
313 if (type == double[].class)
314 return Arrays.hashCode((double[]) value);
315 if (type == float[].class)
316 return Arrays.hashCode((float[]) value);
317 if (type == int[].class)
318 return Arrays.hashCode((int[]) value);
319 if (type == long[].class)
320 return Arrays.hashCode((long[]) value);
321 if (type == short[].class)
322 return Arrays.hashCode((short[]) value);
323 if (type == boolean[].class)
324 return Arrays.hashCode((boolean[]) value);
325 return Arrays.hashCode((Object[]) value);
326 }
327
328 private void readObject(java.io.ObjectInputStream s)
329 throws java.io.IOException, ClassNotFoundException {
330 s.defaultReadObject();
331
332
333 // Check to make sure that types have not evolved incompatibly
334
335 AnnotationType annotationType = null;
336 try {
337 annotationType = AnnotationType.getInstance(type);
338 } catch(IllegalArgumentException e) {
339 // Class is no longer an annotation type; all bets are off
340 return;
341 }
342
343 Map<String, Class> memberTypes = annotationType.memberTypes();
344
345 for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {
346 String name = memberValue.getKey();
347 Class memberType = memberTypes.get(name);
348 if (memberType != null) { // i.e. member still exists
349 Object value = memberValue.getValue();
350 if (!(memberType.isInstance(value) ||
351 value instanceof ExceptionProxy)) {
352 memberValue.setValue(
353 new AnnotationTypeMismatchExceptionProxy(
354 value.getClass() + "[" + value + "]").setMember(
355 annotationType.members().get(name)));
356 }
357 }
358 }
359 }
360 }
|
23 * have any questions.
24 */
25
26 package sun.reflect.annotation;
27
28 import java.lang.annotation.*;
29 import java.lang.reflect.*;
30 import java.io.Serializable;
31 import java.util.*;
32 import java.lang.annotation.*;
33 import java.security.AccessController;
34 import java.security.PrivilegedAction;
35
36 /**
37 * InvocationHandler for dynamic proxy implementation of Annotation.
38 *
39 * @author Josh Bloch
40 * @since 1.5
41 */
42 class AnnotationInvocationHandler implements InvocationHandler, Serializable {
43 private final Class<? extends Annotation> type;
44 private final Map<String, Object> memberValues;
45
46 AnnotationInvocationHandler(Class<? extends Annotation> type, Map<String, Object> memberValues) {
47 this.type = type;
48 this.memberValues = memberValues;
49 }
50
51 public Object invoke(Object proxy, Method method, Object[] args) {
52 String member = method.getName();
53 Class<?>[] paramTypes = method.getParameterTypes();
54
55 // Handle Object and Annotation methods
56 if (member.equals("equals") && paramTypes.length == 1 &&
57 paramTypes[0] == Object.class)
58 return equalsImpl(args[0]);
59 assert paramTypes.length == 0;
60 if (member.equals("toString"))
61 return toStringImpl();
62 if (member.equals("hashCode"))
63 return hashCodeImpl();
64 if (member.equals("annotationType"))
65 return type;
66
67 // Handle annotation member accessors
68 Object result = memberValues.get(member);
69
70 if (result == null)
71 throw new IncompleteAnnotationException(type, member);
72
73 if (result instanceof ExceptionProxy)
74 throw ((ExceptionProxy) result).generateException();
75
76 if (result.getClass().isArray() && Array.getLength(result) != 0)
77 result = cloneArray(result);
78
79 return result;
80 }
81
82 /**
83 * This method, which clones its array argument, would not be necessary
84 * if Cloneable had a public clone method.
85 */
86 private Object cloneArray(Object array) {
87 Class<?> type = array.getClass();
88
89 if (type == byte[].class) {
90 byte[] byteArray = (byte[])array;
91 return byteArray.clone();
92 }
93 if (type == char[].class) {
94 char[] charArray = (char[])array;
95 return charArray.clone();
96 }
97 if (type == double[].class) {
98 double[] doubleArray = (double[])array;
99 return doubleArray.clone();
100 }
101 if (type == float[].class) {
102 float[] floatArray = (float[])array;
103 return floatArray.clone();
104 }
105 if (type == int[].class) {
106 int[] intArray = (int[])array;
107 return intArray.clone();
134 result.append('(');
135 boolean firstMember = true;
136 for (Map.Entry<String, Object> e : memberValues.entrySet()) {
137 if (firstMember)
138 firstMember = false;
139 else
140 result.append(", ");
141
142 result.append(e.getKey());
143 result.append('=');
144 result.append(memberValueToString(e.getValue()));
145 }
146 result.append(')');
147 return result.toString();
148 }
149
150 /**
151 * Translates a member value (in "dynamic proxy return form") into a string
152 */
153 private static String memberValueToString(Object value) {
154 Class<?> type = value.getClass();
155 if (!type.isArray()) // primitive, string, class, enum const,
156 // or annotation
157 return value.toString();
158
159 if (type == byte[].class)
160 return Arrays.toString((byte[]) value);
161 if (type == char[].class)
162 return Arrays.toString((char[]) value);
163 if (type == double[].class)
164 return Arrays.toString((double[]) value);
165 if (type == float[].class)
166 return Arrays.toString((float[]) value);
167 if (type == int[].class)
168 return Arrays.toString((int[]) value);
169 if (type == long[].class)
170 return Arrays.toString((long[]) value);
171 if (type == short[].class)
172 return Arrays.toString((short[]) value);
173 if (type == boolean[].class)
174 return Arrays.toString((boolean[]) value);
212 * Returns null otherwise.
213 */
214 private AnnotationInvocationHandler asOneOfUs(Object o) {
215 if (Proxy.isProxyClass(o.getClass())) {
216 InvocationHandler handler = Proxy.getInvocationHandler(o);
217 if (handler instanceof AnnotationInvocationHandler)
218 return (AnnotationInvocationHandler) handler;
219 }
220 return null;
221 }
222
223 /**
224 * Returns true iff the two member values in "dynamic proxy return form"
225 * are equal using the appropriate equality function depending on the
226 * member type. The two values will be of the same type unless one of
227 * the containing annotations is ill-formed. If one of the containing
228 * annotations is ill-formed, this method will return false unless the
229 * two members are identical object references.
230 */
231 private static boolean memberValueEquals(Object v1, Object v2) {
232 Class<?> type = v1.getClass();
233
234 // Check for primitive, string, class, enum const, annotation,
235 // or ExceptionProxy
236 if (!type.isArray())
237 return v1.equals(v2);
238
239 // Check for array of string, class, enum const, annotation,
240 // or ExceptionProxy
241 if (v1 instanceof Object[] && v2 instanceof Object[])
242 return Arrays.equals((Object[]) v1, (Object[]) v2);
243
244 // Check for ill formed annotation(s)
245 if (v2.getClass() != type)
246 return false;
247
248 // Deal with array of primitives
249 if (type == byte[].class)
250 return Arrays.equals((byte[]) v1, (byte[]) v2);
251 if (type == char[].class)
252 return Arrays.equals((char[]) v1, (char[]) v2);
284 return memberMethods;
285 }
286 private transient volatile Method[] memberMethods = null;
287
288 /**
289 * Implementation of dynamicProxy.hashCode()
290 */
291 private int hashCodeImpl() {
292 int result = 0;
293 for (Map.Entry<String, Object> e : memberValues.entrySet()) {
294 result += (127 * e.getKey().hashCode()) ^
295 memberValueHashCode(e.getValue());
296 }
297 return result;
298 }
299
300 /**
301 * Computes hashCode of a member value (in "dynamic proxy return form")
302 */
303 private static int memberValueHashCode(Object value) {
304 Class<?> type = value.getClass();
305 if (!type.isArray()) // primitive, string, class, enum const,
306 // or annotation
307 return value.hashCode();
308
309 if (type == byte[].class)
310 return Arrays.hashCode((byte[]) value);
311 if (type == char[].class)
312 return Arrays.hashCode((char[]) value);
313 if (type == double[].class)
314 return Arrays.hashCode((double[]) value);
315 if (type == float[].class)
316 return Arrays.hashCode((float[]) value);
317 if (type == int[].class)
318 return Arrays.hashCode((int[]) value);
319 if (type == long[].class)
320 return Arrays.hashCode((long[]) value);
321 if (type == short[].class)
322 return Arrays.hashCode((short[]) value);
323 if (type == boolean[].class)
324 return Arrays.hashCode((boolean[]) value);
325 return Arrays.hashCode((Object[]) value);
326 }
327
328 private void readObject(java.io.ObjectInputStream s)
329 throws java.io.IOException, ClassNotFoundException {
330 s.defaultReadObject();
331
332
333 // Check to make sure that types have not evolved incompatibly
334
335 AnnotationType annotationType = null;
336 try {
337 annotationType = AnnotationType.getInstance(type);
338 } catch(IllegalArgumentException e) {
339 // Class is no longer an annotation type; all bets are off
340 return;
341 }
342
343 Map<String, Class<?>> memberTypes = annotationType.memberTypes();
344
345 for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) {
346 String name = memberValue.getKey();
347 Class<?> memberType = memberTypes.get(name);
348 if (memberType != null) { // i.e. member still exists
349 Object value = memberValue.getValue();
350 if (!(memberType.isInstance(value) ||
351 value instanceof ExceptionProxy)) {
352 memberValue.setValue(
353 new AnnotationTypeMismatchExceptionProxy(
354 value.getClass() + "[" + value + "]").setMember(
355 annotationType.members().get(name)));
356 }
357 }
358 }
359 }
360 }
|