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
33package java.lang.reflect;
34
35import java.lang.annotation.Annotation;
36import java.util.Hashtable;
37
38import org.apache.harmony.kernel.vm.StringUtils;
39import 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 */
60public 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     */
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     */
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     */
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     */
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     */
185    /*package*/ void setAccessibleNoCheck(boolean flag) {
186        this.flag = flag;
187    }
188
189    public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
190        return getAnnotation(annotationType) != null;
191    }
192
193    public Annotation[] getDeclaredAnnotations() {
194        throw new RuntimeException("subclass must override this method");
195    }
196
197    public Annotation[] getAnnotations() {
198        // for all but Class, getAnnotations == getDeclaredAnnotations
199        return getDeclaredAnnotations();
200    }
201
202    /* slow, but works for all sub-classes */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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