OSDN Git Service

original
[gb-231r1-is01/Gingerbread_2.3.3_r1_IS01.git] / libcore / luni / src / main / java / java / lang / ClassCache.java
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package java.lang;
18
19 import java.lang.reflect.AccessibleObject;
20 import java.lang.reflect.Field;
21 import java.lang.reflect.InvocationTargetException;
22 import java.lang.reflect.Method;
23 import java.util.ArrayList;
24 import java.util.Arrays;
25 import java.util.Collections;
26 import java.util.Comparator;
27 import java.util.EnumSet;
28 import java.util.HashSet;
29 import java.util.List;
30 import org.apache.harmony.kernel.vm.LangAccess;
31 import org.apache.harmony.kernel.vm.ReflectionAccess;
32
33 /**
34  * Cache of per-class data, meant to help the performance of reflection
35  * methods.
36  *
37  * <p><b>Note:</b> None of the methods perform access checks. It is up
38  * to the (package internal) clients of this code to perform such
39  * checks as necessary.</p>
40  *
41  * <p><b>Also Note:</b> None of the returned array values are
42  * protected in any way. It is up to the (again, package internal)
43  * clients of this code to protect the arrays if they should ever
44  * escape the package.</p>
45  */
46 /*package*/ class ClassCache<T> {
47     // TODO: Add caching for constructors and fields.
48
49     /** non-null; comparator used for enumerated values */
50     private static final EnumComparator ENUM_COMPARATOR =
51         new EnumComparator();
52
53     /** non-null; reflection access bridge */
54     /*package*/ static final ReflectionAccess REFLECT = getReflectionAccess();
55
56     /** non-null; class that this instance represents */
57     private final Class<T> clazz;
58
59     /** null-ok; list of all public methods, both direct and inherited */
60     private volatile Method[] methods;
61
62     /** null-ok; list of all declared methods */
63     private volatile Method[] declaredMethods;
64
65     /** null-ok; list of all public declared methods */
66     private volatile Method[] declaredPublicMethods;
67
68     /** null-ok; list of all declared fields */
69     private volatile Field[] declaredFields;
70
71     /** null-ok; list of all public declared fields */
72     private volatile Field[] declaredPublicFields;
73
74     /** null-ok; list of all fields, both direct and inherited */
75     private volatile Field[] allFields;
76
77     /** null-ok; list of all public fields, both direct and inherited */
78     private volatile Field[] allPublicFields;
79
80     /**
81      * null-ok; array of enumerated values in their original order, if this
82      * instance's class is an enumeration
83      */
84     private volatile T[] enumValuesInOrder;
85
86     /**
87      * null-ok; array of enumerated values sorted by name, if this
88      * instance's class is an enumeration
89      */
90     private volatile T[] enumValuesByName;
91
92     static {
93         /*
94          * Provide access to this package from java.util as part of
95          * bootstrap. TODO: See if this can be removed in favor of the
96          * simpler mechanism below. (That is, see if EnumSet will be
97          * happy calling LangAccess.getInstance().)
98          */
99         Field field;
100
101         try {
102             field = EnumSet.class.getDeclaredField("LANG_BOOTSTRAP");
103             REFLECT.setAccessibleNoCheck(field, true);
104         } catch (NoSuchFieldException ex) {
105             // This shouldn't happen because the field is in fact defined.
106             throw new AssertionError(ex);
107         }
108
109         try {
110             field.set(null, LangAccessImpl.THE_ONE);
111         } catch (IllegalAccessException ex) {
112             // This shouldn't happen because we made the field accessible.
113             throw new AssertionError(ex);
114         }
115
116         // Also set up the bootstrap-classpath-wide access mechanism.
117         LangAccess.setInstance(LangAccessImpl.THE_ONE);
118     }
119
120     /**
121      * Constructs an instance.
122      *
123      * @param clazz non-null; class that this instance represents
124      */
125     /*package*/ ClassCache(Class<T> clazz) {
126         if (clazz == null) {
127             throw new NullPointerException("clazz == null");
128         }
129
130         this.clazz = clazz;
131     }
132
133     /**
134      * Gets the list of all declared methods.
135      *
136      * @return non-null; the list of all declared methods
137      */
138     public Method[] getDeclaredMethods() {
139         if (declaredMethods == null) {
140             declaredMethods = Class.getDeclaredMethods(clazz, false);
141         }
142
143         return declaredMethods;
144     }
145
146     /**
147      * Gets the list of all declared public methods.
148      *
149      * @return non-null; the list of all declared public methods
150      */
151     private Method[] getDeclaredPublicMethods() {
152         if (declaredPublicMethods == null) {
153             declaredPublicMethods = Class.getDeclaredMethods(clazz, true);
154         }
155
156         return declaredPublicMethods;
157     }
158
159     /**
160      * Returns public methods defined by {@code clazz}, its superclasses and all
161      * implemented interfaces, not including overridden methods. This method
162      * performs no security checks.
163      */
164     public Method[] getMethods() {
165         Method[] cachedResult = methods;
166         if (cachedResult == null) {
167             methods = findMethods();
168         }
169
170         return methods;
171     }
172
173     private Method[] findMethods() {
174         List<Method> allMethods = new ArrayList<Method>();
175         getMethodsRecursive(clazz, allMethods);
176
177         /*
178          * Remove methods defined by multiple types, preferring to keep methods
179          * declared by derived types.
180          *
181          * Classes may define multiple methods with the same name and parameter
182          * types due to covariant return types. In this case both are returned,
183          * with the non-synthetic method first because it is preferred by
184          * getMethod(String,Class[]).
185          */
186         Collections.sort(allMethods, Method.ORDER_BY_SIGNATURE);
187         List<Method> natural = new ArrayList<Method>(allMethods.size());
188         List<Method> synthetic = new ArrayList<Method>(allMethods.size());
189         Method previous = null;
190         for (Method method : allMethods) {
191             if (previous != null
192                     && Method.ORDER_BY_SIGNATURE.compare(method, previous) == 0
193                     && method.getDeclaringClass() != previous.getDeclaringClass()) {
194                 continue;
195             }
196             if (method.isSynthetic()) {
197                 synthetic.add(method);
198             } else {
199                 natural.add(method);
200             }
201             previous = method;
202         }
203         List<Method> result = new ArrayList<Method>(allMethods.size());
204         result.addAll(natural);
205         result.addAll(synthetic);
206         return result.toArray(new Method[result.size()]);
207     }
208
209     /**
210      * Populates {@code sink} with public methods defined by {@code clazz}, its
211      * superclasses, and all implemented interfaces, including overridden methods.
212      * This method performs no security checks.
213      */
214     private static void getMethodsRecursive(Class<?> clazz, List<Method> result) {
215         for (Class<?> c = clazz; c != null; c = c.getSuperclass()) {
216             for (Method method : c.getClassCache().getDeclaredPublicMethods()) {
217                 result.add(method);
218             }
219         }
220
221         for (Class<?> ifc : clazz.getInterfaces()) {
222             getMethodsRecursive(ifc, result);
223         }
224     }
225
226     /**
227      * Finds and returns a method with a given name and signature. Use
228      * this with one of the method lists returned by instances of this class.
229      *
230      * @param list non-null; the list of methods to search through
231      * @param parameterTypes non-null; the formal parameter list
232      * @return non-null; the matching method
233      * @throws NoSuchMethodException thrown if the method does not exist
234      */
235     public static Method findMethodByName(Method[] list, String name,
236             Class<?>[] parameterTypes) throws NoSuchMethodException {
237         if (name == null) {
238             throw new NullPointerException("Method name must not be null.");
239         }
240         for (Method method : list) {
241             if (method.getName().equals(name)
242                     && compareClassLists(method.getParameterTypes(), parameterTypes)) {
243                 return method;
244             }
245         }
246
247         throw new NoSuchMethodException(name);
248     }
249
250     /**
251      * Compares two class lists for equality. Empty and
252      * <code>null</code> lists are considered equal. This is useful
253      * for matching methods and constructors.
254      *
255      * <p>TODO: Take into account assignment compatibility?</p>
256      *
257      * @param a null-ok; the first list of types
258      * @param b null-ok; the second list of types
259      * @return true if and only if the lists are equal
260      */
261     public static boolean compareClassLists(Class<?>[] a, Class<?>[] b) {
262         if (a == null) {
263             return (b == null) || (b.length == 0);
264         }
265
266         int length = a.length;
267
268         if (b == null) {
269             return (length == 0);
270         }
271
272         if (length != b.length) {
273             return false;
274         }
275
276         for (int i = length - 1; i >= 0; i--) {
277             if (a[i] != b[i]) {
278                 return false;
279             }
280         }
281
282         return true;
283     }
284
285     /**
286      * Makes a deep copy of the given array of methods. This is useful
287      * when handing out arrays from the public API.
288      *
289      * <p><b>Note:</b> In such cases, it is insufficient to just make
290      * a shallow copy of the array, since method objects aren't
291      * immutable due to the existence of {@link
292      * AccessibleObject#setAccessible}.</p>
293      *
294      * @param orig non-null; array to copy
295      * @return non-null; a deep copy of the given array
296      */
297     public static Method[] deepCopy(Method[] orig) {
298         int length = orig.length;
299         Method[] result = new Method[length];
300
301         for (int i = length - 1; i >= 0; i--) {
302             result[i] = REFLECT.clone(orig[i]);
303         }
304
305         return result;
306     }
307
308     /**
309      * Gets the list of all declared fields.
310      *
311      * @return non-null; the list of all declared fields
312      */
313     public Field[] getDeclaredFields() {
314         if (declaredFields == null) {
315             declaredFields = Class.getDeclaredFields(clazz, false);
316         }
317
318         return declaredFields;
319     }
320
321     /**
322      * Gets the list of all declared public fields.
323      *
324      * @return non-null; the list of all declared public fields
325      */
326     public Field[] getDeclaredPublicFields() {
327         if (declaredPublicFields == null) {
328             declaredPublicFields = Class.getDeclaredFields(clazz, true);
329         }
330
331         return declaredPublicFields;
332     }
333
334     /**
335      * Gets either the list of declared fields or the list of declared
336      * public fields.
337      *
338      * @param publicOnly whether to only return public fields
339      */
340     public Field[] getDeclaredFields(boolean publicOnly) {
341         return publicOnly ? getDeclaredPublicFields() : getDeclaredFields();
342     }
343
344     /**
345      * Gets the list of all fields, both directly
346      * declared and inherited.
347      *
348      * @return non-null; the list of all fields
349      */
350     public Field[] getAllFields() {
351         if (allFields == null) {
352             allFields = getFullListOfFields(false);
353         }
354
355         return allFields;
356     }
357
358     /**
359      * Gets the list of all public fields, both directly
360      * declared and inherited.
361      *
362      * @return non-null; the list of all public fields
363      */
364     public Field[] getAllPublicFields() {
365         if (allPublicFields == null) {
366             allPublicFields = getFullListOfFields(true);
367         }
368
369         return allPublicFields;
370     }
371
372     /*
373      * Returns the list of fields without performing any security checks
374      * first. This includes the fields inherited from superclasses. If no
375      * fields exist at all, an empty array is returned.
376      *
377      * @param publicOnly reflects whether we want only public fields
378      * or all of them
379      * @return the list of fields
380      */
381     private Field[] getFullListOfFields(boolean publicOnly) {
382         ArrayList<Field> fields = new ArrayList<Field>();
383         HashSet<String> seen = new HashSet<String>();
384
385         findAllfields(clazz, fields, seen, publicOnly);
386
387         return fields.toArray(new Field[fields.size()]);
388     }
389
390     /**
391      * Collects the list of fields without performing any security checks
392      * first. This includes the fields inherited from superclasses and from
393      * all implemented interfaces. The latter may also implement multiple
394      * interfaces, so we (potentially) recursively walk through a whole tree of
395      * classes. If no fields exist at all, an empty array is returned.
396      *
397      * @param clazz non-null; class to inspect
398      * @param fields non-null; the target list to add the results to
399      * @param seen non-null; a set of signatures we've already seen
400      * @param publicOnly reflects whether we want only public fields
401      * or all of them
402      */
403     private static void findAllfields(Class<?> clazz,
404             ArrayList<Field> fields, HashSet<String> seen,
405             boolean publicOnly) {
406
407         // Traverse class and superclasses, get rid of dupes by signature
408         while (clazz != null) {
409             for (Field field : clazz.getClassCache().getDeclaredFields(publicOnly)) {
410                 String signature = field.toString();
411                 if (!seen.contains(signature)) {
412                     fields.add(field);
413                     seen.add(signature);
414                 }
415             }
416
417             // Traverse all interfaces, and do the same recursively.
418             Class<?>[] interfaces = clazz.getInterfaces();
419             for (Class<?> intf : interfaces) {
420                 findAllfields(intf, fields, seen, publicOnly);
421             }
422
423             clazz = clazz.getSuperclass();
424         }
425     }
426
427     /**
428      * Finds and returns a field with a given name and signature. Use
429      * this with one of the field lists returned by instances of this class.
430      *
431      * @param list non-null; the list of fields to search through
432      * @return non-null; the matching field
433      * @throws NoSuchFieldException thrown if the field does not exist
434      */
435     public static Field findFieldByName(Field[] list, String name)
436             throws NoSuchFieldException {
437         if (name == null) {
438             throw new NullPointerException("Field name must not be null.");
439         }
440         for (Field field : list) {
441             if (field.getName().equals(name)) {
442                 return field;
443             }
444         }
445
446         throw new NoSuchFieldException(name);
447     }
448
449     /**
450      * Makes a deep copy of the given array of fields. This is useful
451      * when handing out arrays from the public API.
452      *
453      * <p><b>Note:</b> In such cases, it is insufficient to just make
454      * a shallow copy of the array, since field objects aren't
455      * immutable due to the existence of {@link
456      * AccessibleObject#setAccessible}.</p>
457      *
458      * @param orig non-null; array to copy
459      * @return non-null; a deep copy of the given array
460      */
461     public static Field[] deepCopy(Field[] orig) {
462         int length = orig.length;
463         Field[] result = new Field[length];
464
465         for (int i = length - 1; i >= 0; i--) {
466             result[i] = REFLECT.clone(orig[i]);
467         }
468
469         return result;
470     }
471
472     /**
473      * Gets the enumerated value with a given name.
474      *
475      * @param name non-null; name of the value
476      * @return null-ok; the named enumerated value or <code>null</code>
477      * if this instance's class doesn't have such a value (including
478      * if this instance isn't in fact an enumeration)
479      */
480     @SuppressWarnings("unchecked")
481     public T getEnumValue(String name) {
482         Enum[] values = (Enum[]) getEnumValuesByName();
483
484         if (values == null) {
485             return null;
486         }
487
488         // Binary search.
489
490         int min = 0;
491         int max = values.length - 1;
492
493         while (min <= max) {
494             /*
495              * The guessIdx calculation is equivalent to ((min + max)
496              * / 2) but won't go wonky when min and max are close to
497              * Integer.MAX_VALUE.
498              */
499             int guessIdx = min + ((max - min) >> 1);
500             Enum guess = values[guessIdx];
501             int cmp = name.compareTo(guess.name());
502
503             if (cmp < 0) {
504                 max = guessIdx - 1;
505             } else if (cmp > 0) {
506                 min = guessIdx + 1;
507             } else {
508                 return (T) guess;
509             }
510         }
511
512         return null;
513     }
514
515     /**
516      * Gets the array of enumerated values, sorted by name.
517      *
518      * @return null-ok; the value array, or <code>null</code> if this
519      * instance's class isn't in fact an enumeration
520      */
521     public T[] getEnumValuesByName() {
522         if (enumValuesByName == null) {
523             T[] values = getEnumValuesInOrder();
524
525             if (values != null) {
526                 values = (T[]) values.clone();
527                 Arrays.sort((Enum<?>[]) values, ENUM_COMPARATOR);
528
529                 /*
530                  * Note: It's only safe (concurrency-wise) to set the
531                  * instance variable after the array is properly sorted.
532                  */
533                 enumValuesByName = values;
534             }
535         }
536
537         return enumValuesByName;
538     }
539
540     /**
541      * Gets the array of enumerated values, in their original declared
542      * order.
543      *
544      * @return null-ok; the value array, or <code>null</code> if this
545      * instance's class isn't in fact an enumeration
546      */
547     public T[] getEnumValuesInOrder() {
548         if ((enumValuesInOrder == null) && clazz.isEnum()) {
549             enumValuesInOrder = callEnumValues();
550         }
551
552         return enumValuesInOrder;
553     }
554
555     /**
556      * Calls the static method <code>values()</code> on this
557      * instance's class, which is presumed to be a properly-formed
558      * enumeration class, using proper privilege hygiene.
559      *
560      * @return non-null; the array of values as reported by
561      * <code>value()</code>
562      */
563     @SuppressWarnings("unchecked")
564     private T[] callEnumValues() {
565         Method method;
566
567         try {
568             Method[] methods = getDeclaredPublicMethods();
569             method = findMethodByName(methods, "values", (Class[]) null);
570             method = REFLECT.accessibleClone(method);
571         } catch (NoSuchMethodException ex) {
572             // This shouldn't happen if the class is a well-formed enum.
573             throw new UnsupportedOperationException(ex);
574         }
575
576         try {
577             return (T[]) method.invoke((Object[]) null);
578         } catch (IllegalAccessException ex) {
579             // This shouldn't happen because the method is "accessible."
580             throw new Error(ex);
581         } catch (InvocationTargetException ex) {
582             Throwable te = ex.getTargetException();
583             if (te instanceof RuntimeException) {
584                 throw (RuntimeException) te;
585             } else if (te instanceof Error) {
586                 throw (Error) te;
587             } else {
588                 throw new Error(te);
589             }
590         }
591     }
592
593     /**
594      * Gets the reflection access object. This uses reflection to do
595      * so. My head is spinning.
596      *
597      * @return non-null; the reflection access object
598      */
599     private static ReflectionAccess getReflectionAccess() {
600         /*
601          * Note: We can't do AccessibleObject.class.getCache() to
602          * get the cache, since that would cause a circularity in
603          * initialization. So instead, we do a direct call into the
604          * native side.
605          */
606         Method[] methods =
607             Class.getDeclaredMethods(AccessibleObject.class, false);
608
609         try {
610             Method method = findMethodByName(methods, "getReflectionAccess",
611                     (Class[]) null);
612             Class.setAccessibleNoCheck(method, true);
613             return (ReflectionAccess) method.invoke((Object[]) null);
614         } catch (NoSuchMethodException ex) {
615             /*
616              * This shouldn't happen because the method
617              * AccessibleObject.getReflectionAccess() really is defined
618              * in this module.
619              */
620             throw new Error(ex);
621         } catch (IllegalAccessException ex) {
622             // This shouldn't happen because the method is "accessible."
623             throw new Error(ex);
624         } catch (InvocationTargetException ex) {
625             throw new Error(ex);
626         }
627     }
628
629     /**
630      * Comparator class for enumerated values. It compares strictly
631      * by name.
632      */
633     private static class EnumComparator implements Comparator<Enum<?>> {
634         public int compare(Enum<?> e1, Enum<?> e2) {
635             return e1.name().compareTo(e2.name());
636         }
637     }
638 }