History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/reflect/annotation/AnnotationInvocationHandler.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/reflect/annotation/AnnotationInvocationHandler.java+360−0
@@ -0,0 +1,360 @@
1+/*
2+ * Copyright (c) 2003, 2008, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * 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();
108+ }
109+ if (type == long[].class) {
110+ long[] longArray = (long[])array;
111+ return longArray.clone();
112+ }
113+ if (type == short[].class) {
114+ short[] shortArray = (short[])array;
115+ return shortArray.clone();
116+ }
117+ if (type == boolean[].class) {
118+ boolean[] booleanArray = (boolean[])array;
119+ return booleanArray.clone();
120+ }
121+
122+ Object[] objectArray = (Object[])array;
123+ return objectArray.clone();
124+ }
125+
126+
127+ /**
128+ * Implementation of dynamicProxy.toString()
129+ */
130+ private String toStringImpl() {
131+ StringBuffer result = new StringBuffer(128);
132+ result.append('@');
133+ result.append(type.getName());
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);
175+ return Arrays.toString((Object[]) value);
176+ }
177+
178+ /**
179+ * Implementation of dynamicProxy.equals(Object o)
180+ */
181+ private Boolean equalsImpl(Object o) {
182+ if (o == this)
183+ return true;
184+
185+ if (!type.isInstance(o))
186+ return false;
187+ for (Method memberMethod : getMemberMethods()) {
188+ String member = memberMethod.getName();
189+ Object ourValue = memberValues.get(member);
190+ Object hisValue = null;
191+ AnnotationInvocationHandler hisHandler = asOneOfUs(o);
192+ if (hisHandler != null) {
193+ hisValue = hisHandler.memberValues.get(member);
194+ } else {
195+ try {
196+ hisValue = memberMethod.invoke(o);
197+ } catch (InvocationTargetException e) {
198+ return false;
199+ } catch (IllegalAccessException e) {
200+ throw new AssertionError(e);
201+ }
202+ }
203+ if (!memberValueEquals(ourValue, hisValue))
204+ return false;
205+ }
206+ return true;
207+ }
208+
209+ /**
210+ * Returns an object's invocation handler if that object is a dynamic
211+ * proxy with a handler of type AnnotationInvocationHandler.
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);
253+ if (type == double[].class)
254+ return Arrays.equals((double[]) v1, (double[]) v2);
255+ if (type == float[].class)
256+ return Arrays.equals((float[]) v1, (float[]) v2);
257+ if (type == int[].class)
258+ return Arrays.equals((int[]) v1, (int[]) v2);
259+ if (type == long[].class)
260+ return Arrays.equals((long[]) v1, (long[]) v2);
261+ if (type == short[].class)
262+ return Arrays.equals((short[]) v1, (short[]) v2);
263+ assert type == boolean[].class;
264+ return Arrays.equals((boolean[]) v1, (boolean[]) v2);
265+ }
266+
267+ /**
268+ * Returns the member methods for our annotation type. These are
269+ * obtained lazily and cached, as they're expensive to obtain
270+ * and we only need them if our equals method is invoked (which should
271+ * be rare).
272+ */
273+ private Method[] getMemberMethods() {
274+ if (memberMethods == null) {
275+ memberMethods = AccessController.doPrivileged(
276+ new PrivilegedAction<Method[]>() {
277+ public Method[] run() {
278+ final Method[] mm = type.getDeclaredMethods();
279+ AccessibleObject.setAccessible(mm, true);
280+ return mm;
281+ }
282+ });
283+ }
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+}