• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 /*
18  * Copyright (C) 2008 The Android Open Source Project
19  *
20  * Licensed under the Apache License, Version 2.0 (the "License");
21  * you may not use this file except in compliance with the License.
22  * You may obtain a copy of the License at
23  *
24  *      http://www.apache.org/licenses/LICENSE-2.0
25  *
26  * Unless required by applicable law or agreed to in writing, software
27  * distributed under the License is distributed on an "AS IS" BASIS,
28  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29  * See the License for the specific language governing permissions and
30  * limitations under the License.
31  */
32 
33 package java.lang.reflect;
34 
35 import java.lang.annotation.Annotation;
36 import java.util.Hashtable;
37 
38 import org.apache.harmony.kernel.vm.StringUtils;
39 import org.apache.harmony.kernel.vm.ReflectionAccess;
40 
41 /**
42  * {@code AccessibleObject} is the superclass of all member reflection classes
43  * (Field, Constructor, Method). AccessibleObject provides the ability to toggle
44  * a flag controlling access checks for these objects. By default, accessing a
45  * member (for example, setting a field or invoking a method) checks the
46  * validity of the access (for example, invoking a private method from outside
47  * the defining class is prohibited) and throws IllegalAccessException if the
48  * operation is not permitted. If the accessible flag is set to true, these
49  * checks are omitted. This allows privileged code, such as Java object
50  * serialization, object inspectors, and debuggers to have complete access to
51  * objects.
52  *
53  * @see Field
54  * @see Constructor
55  * @see Method
56  * @see ReflectPermission
57  *
58  * @since Android 1.0
59  */
60 public class AccessibleObject implements AnnotatedElement {
61 
62     // If true, object is accessible, bypassing normal security checks
63     boolean flag = false;
64 
65     /**
66      * one dimensional array
67      */
68     private static final String DIMENSION_1 = "[]";
69 
70     /**
71      * two dimensional array
72      */
73     private static final String DIMENSION_2 = "[][]";
74 
75     /**
76      * three dimensional array
77      */
78     private static final String DIMENSION_3 = "[][][]";
79 
80     // Holds a mapping from Java type names to native type codes.
81     static Hashtable<String, String> trans;
82 
83     static {
84         trans = new Hashtable<String, String>(9);
85         trans.put("byte", "B");
86         trans.put("char", "C");
87         trans.put("short", "S");
88         trans.put("int", "I");
89         trans.put("long", "J");
90         trans.put("float", "F");
91         trans.put("double", "D");
92         trans.put("void", "V");
93         trans.put("boolean", "Z");
94     }
95 
96     /**
97      * Attempts to set the value of the accessible flag for all the objects in
98      * the array provided. Only one security check is performed. Setting this
99      * flag to {@code false} will enable access checks, setting to {@code true}
100      * will disable them. If there is a security manager, checkPermission is
101      * called with a {@code ReflectPermission("suppressAccessChecks")}.
102      *
103      * @param objects
104      *            the accessible objects
105      * @param flag
106      *            the new value for the accessible flag
107      *
108      * @throws SecurityException
109      *             if the request is denied
110      *
111      * @see #setAccessible(boolean)
112      * @see ReflectPermission
113      *
114      * @since Android 1.0
115      */
setAccessible(AccessibleObject[] objects, boolean flag)116     public static void setAccessible(AccessibleObject[] objects, boolean flag)
117             throws SecurityException {
118         SecurityManager smgr = System.getSecurityManager();
119         if (smgr != null) {
120             smgr.checkPermission(new ReflectPermission("suppressAccessChecks"));
121         }
122 
123         synchronized(AccessibleObject.class) {
124             for (int i = 0; i < objects.length; i++) {
125                 objects[i].flag = flag;
126             }
127         }
128     }
129 
130     /**
131      * Constructs a new {@code AccessibleObject} instance. {@code
132      * AccessibleObject} instances can only be constructed by the virtual
133      * machine.
134      *
135      * @since Android 1.0
136      */
AccessibleObject()137     protected AccessibleObject() {
138         super();
139     }
140 
141     /**
142      * Indicates whether this object is accessible without security checks being
143      * performed. Returns the accessible flag.
144      *
145      * @return {@code true} if this object is accessible without security
146      *         checks, {@code false} otherwise
147      *
148      * @since Android 1.0
149      */
isAccessible()150     public boolean isAccessible() {
151         return flag;
152     }
153 
154     /**
155      * Attempts to set the value of the accessible flag. Setting this flag to
156      * {@code false} will enable access checks, setting to {@code true} will
157      * disable them. If there is a security manager, checkPermission is called
158      * with a {@code ReflectPermission("suppressAccessChecks")}.
159      *
160      * @param flag
161      *            the new value for the accessible flag
162      *
163      * @throws SecurityException
164      *             if the request is denied
165      *
166      * @see ReflectPermission
167      *
168      * @since Android 1.0
169      */
setAccessible(boolean flag)170     public void setAccessible(boolean flag) throws SecurityException {
171         SecurityManager smgr = System.getSecurityManager();
172         if (smgr != null) {
173             smgr.checkPermission(new ReflectPermission("suppressAccessChecks"));
174         }
175 
176         this.flag = flag;
177     }
178 
179     /**
180      * Sets the accessible flag on this instance without doing any checks.
181      *
182      * @param flag
183      *            the new value for the accessible flag
184      */
setAccessibleNoCheck(boolean flag)185     /*package*/ void setAccessibleNoCheck(boolean flag) {
186         this.flag = flag;
187     }
188 
isAnnotationPresent(Class<? extends Annotation> annotationType)189     public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
190         return getAnnotation(annotationType) != null;
191     }
192 
getDeclaredAnnotations()193     public Annotation[] getDeclaredAnnotations() {
194         throw new RuntimeException("subclass must override this method");
195     }
196 
getAnnotations()197     public Annotation[] getAnnotations() {
198         // for all but Class, getAnnotations == getDeclaredAnnotations
199         return getDeclaredAnnotations();
200     }
201 
202     /* slow, but works for all sub-classes */
getAnnotation(Class<T> annotationType)203     public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
204         if (annotationType == null) {
205             throw new NullPointerException();
206         }
207         Annotation[] annos = getAnnotations();
208         for (int i = annos.length-1; i >= 0; --i) {
209             if (annos[i].annotationType() == annotationType) {
210                 return (T) annos[i];
211             }
212         }
213         return null;
214     }
215 
216     /**
217      * Returns the signature for a class. This is the kind of signature used
218      * internally by the JVM, with one-character codes representing the basic
219      * types. It is not suitable for printing.
220      *
221      * @param clazz
222      *            the class for which a signature is required
223      *
224      * @return The signature as a string
225      */
getSignature(Class<?> clazz)226     String getSignature(Class<?> clazz) {
227         String result = "";
228         String nextType = clazz.getName();
229 
230         if(trans.containsKey(nextType)) {
231             result = trans.get(nextType);
232         } else {
233             if(clazz.isArray()) {
234                 result = "[" + getSignature(clazz.getComponentType());
235             } else {
236                 result = "L" + nextType + ";";
237             }
238         }
239         return result;
240     }
241 
242     /**
243      * Returns a printable String consisting of the canonical names of the
244      * classes contained in an array. The form is that used in parameter and
245      * exception lists, that is, the class or type names are separated by
246      * commas.
247      *
248      * @param types
249      *            the array of classes
250      *
251      * @return The String of names
252      */
toString(Class<?>[] types)253     String toString(Class<?>[] types) {
254         StringBuilder result = new StringBuilder();
255 
256         if (types.length != 0) {
257             result.append(types[0].getCanonicalName());
258             for (int i = 1; i < types.length; i++) {
259                 result.append(',');
260                 result.append(types[i].getCanonicalName());
261             }
262         }
263 
264         return result.toString();
265     }
266 
267     /**
268      * Gets the Signature attribute for this instance. Returns {@code null}
269      * if not found.
270      */
getSignatureAttribute()271     /*package*/ String getSignatureAttribute() {
272         /*
273          * Note: This method would have been declared abstract, but the
274          * standard API lists this class as concrete.
275          */
276         throw new UnsupportedOperationException();
277     }
278 
279     /**
280      * Retrieve the signature attribute from an arbitrary class.  This is
281      * the same as Class.getSignatureAttribute(), but it can be used from
282      * the java.lang.reflect package.
283      */
getClassSignatureAttribute(Class clazz)284     /*package*/ static String getClassSignatureAttribute(Class clazz) {
285         Object[] annotation = getClassSignatureAnnotation(clazz);
286 
287         if (annotation == null) {
288             return null;
289         }
290 
291         return StringUtils.combineStrings(annotation);
292     }
293 
294     /**
295      * Retrieve the signature annotation from an arbitrary class.  This is
296      * the same as Class.getSignatureAttribute(), but it can be used from
297      * the java.lang.reflect package.
298      */
getClassSignatureAnnotation(Class clazz)299     private static native Object[] getClassSignatureAnnotation(Class clazz);
300 
301     /**
302      * Gets the unique instance of {@link ReflectionAccessImpl}.
303      *
304      * @return non-null; the unique instance
305      */
getReflectionAccess()306     static /*package*/ ReflectionAccess getReflectionAccess() {
307         return ReflectionAccessImpl.THE_ONE;
308     }
309 
310 
311     /**
312      * Appends the specified class name to the buffer. The class may represent
313      * a simple type, a reference type or an array type.
314      *
315      * @param sb buffer
316      * @param obj the class which name should be appended to the buffer
317      *
318      * @throws NullPointerException if any of the arguments is null
319      */
appendArrayType(StringBuilder sb, Class<?> obj)320     void appendArrayType(StringBuilder sb, Class<?> obj) {
321         if (!obj.isArray()) {
322             sb.append(obj.getName());
323             return;
324         }
325         int dimensions = 1;
326         Class simplified = obj.getComponentType();
327         obj = simplified;
328         while (simplified.isArray()) {
329             obj = simplified;
330             dimensions++;
331         }
332         sb.append(obj.getName());
333         switch (dimensions) {
334         case 1:
335             sb.append(DIMENSION_1);
336             break;
337         case 2:
338             sb.append(DIMENSION_2);
339             break;
340         case 3:
341             sb.append(DIMENSION_3);
342             break;
343         default:
344             for (; dimensions > 0; dimensions--) {
345                 sb.append(DIMENSION_1);
346             }
347         }
348     }
349 
350     /**
351      * Appends names of the specified array classes to the buffer. The array
352      * elements may represent a simple type, a reference type or an array type.
353      * Output format: java.lang.Object[], java.io.File, void
354      *
355      * @param sb buffer
356      * @param objs array of classes to print the names
357      *
358      * @throws NullPointerException if any of the arguments is null
359      */
appendArrayType(StringBuilder sb, Class[] objs)360     void appendArrayType(StringBuilder sb, Class[] objs) {
361         if (objs.length > 0) {
362             appendArrayType(sb, objs[0]);
363             for (int i = 1; i < objs.length; i++) {
364                 sb.append(',');
365                 appendArrayType(sb, objs[i]);
366             }
367         }
368     }
369 
370     /**
371      * Appends names of the specified array classes to the buffer. The array
372      * elements may represent a simple type, a reference type or an array type.
373      * Output format: java.lang.Object[], java.io.File, void
374      *
375      * @param sb buffer
376      * @param objs array of classes to print the names
377      *
378      * @throws NullPointerException if any of the arguments is null
379      */
appendArrayGenericType(StringBuilder sb, Type[] objs)380     void appendArrayGenericType(StringBuilder sb, Type[] objs) {
381         if (objs.length > 0) {
382             appendGenericType(sb, objs[0]);
383             for (int i = 1; i < objs.length; i++) {
384                 sb.append(',');
385                 appendGenericType(sb, objs[i]);
386             }
387         }
388     }
389 
390     /**
391      * Appends the generic type representation to the buffer.
392      *
393      * @param sb buffer
394      * @param obj the generic type which representation should be appended to the buffer
395      *
396      * @throws NullPointerException if any of the arguments is null
397      */
appendGenericType(StringBuilder sb, Type obj)398     void appendGenericType(StringBuilder sb, Type obj) {
399         if (obj instanceof TypeVariable) {
400             sb.append(((TypeVariable)obj).getName());
401         } else if (obj instanceof ParameterizedType) {
402             sb.append(obj.toString());
403         } else if (obj instanceof GenericArrayType) { //XXX: is it a working branch?
404             Type simplified = ((GenericArrayType)obj).getGenericComponentType();
405             appendGenericType(sb, simplified);
406             sb.append("[]");
407         } else if (obj instanceof Class) {
408             Class c = ((Class<?>)obj);
409             if (c.isArray()){
410                 String as[] = c.getName().split("\\[");
411                 int len = as.length-1;
412                 if (as[len].length() > 1){
413                     sb.append(as[len].substring(1, as[len].length()-1));
414                 } else {
415                     char ch = as[len].charAt(0);
416                     if (ch == 'I')
417                         sb.append("int");
418                     else if (ch == 'B')
419                         sb.append("byte");
420                     else if (ch == 'J')
421                         sb.append("long");
422                     else if (ch == 'F')
423                         sb.append("float");
424                     else if (ch == 'D')
425                         sb.append("double");
426                     else if (ch == 'S')
427                         sb.append("short");
428                     else if (ch == 'C')
429                         sb.append("char");
430                     else if (ch == 'Z')
431                         sb.append("boolean");
432                     else if (ch == 'V') //XXX: is it a working branch?
433                         sb.append("void");
434                 }
435                 for (int i = 0; i < len; i++){
436                     sb.append("[]");
437                 }
438             } else {
439                 sb.append(c.getName());
440             }
441         }
442     }
443 
444     /**
445      * Appends names of the specified array classes to the buffer. The array
446      * elements may represent a simple type, a reference type or an array type.
447      * In case if the specified array element represents an array type its
448      * internal will be appended to the buffer.
449      * Output format: [Ljava.lang.Object;, java.io.File, void
450      *
451      * @param sb buffer
452      * @param objs array of classes to print the names
453      *
454      * @throws NullPointerException if any of the arguments is null
455      */
appendSimpleType(StringBuilder sb, Class<?>[] objs)456     void appendSimpleType(StringBuilder sb, Class<?>[] objs) {
457         if (objs.length > 0) {
458             sb.append(objs[0].getName());
459             for (int i = 1; i < objs.length; i++) {
460                 sb.append(',');
461                 sb.append(objs[i].getName());
462             }
463         }
464     }
465 }
466