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;
37import org.apache.harmony.kernel.vm.StringUtils;
38
39/**
40 * {@code AccessibleObject} is the superclass of all member reflection classes
41 * (Field, Constructor, Method). AccessibleObject provides the ability to toggle
42 * a flag controlling access checks for these objects. By default, accessing a
43 * member (for example, setting a field or invoking a method) checks the
44 * validity of the access (for example, invoking a private method from outside
45 * the defining class is prohibited) and throws IllegalAccessException if the
46 * operation is not permitted. If the accessible flag is set to true, these
47 * checks are omitted. This allows privileged code, such as Java object
48 * serialization, object inspectors, and debuggers to have complete access to
49 * objects.
50 *
51 * @see Field
52 * @see Constructor
53 * @see Method
54 */
55public class AccessibleObject implements AnnotatedElement {
56
57    // If true, object is accessible, bypassing normal access checks
58    boolean flag = false;
59
60    // Holds a mapping from Java type names to native type codes.
61    static Hashtable<String, String> trans;
62
63    static {
64        trans = new Hashtable<String, String>(9);
65        trans.put("byte", "B");
66        trans.put("char", "C");
67        trans.put("short", "S");
68        trans.put("int", "I");
69        trans.put("long", "J");
70        trans.put("float", "F");
71        trans.put("double", "D");
72        trans.put("void", "V");
73        trans.put("boolean", "Z");
74    }
75
76    /**
77     * Attempts to set the value of the accessible flag for all the objects in
78     * the array provided. Setting this
79     * flag to {@code false} will enable access checks, setting to {@code true}
80     * will disable them.
81     *
82     * @param objects
83     *            the accessible objects
84     * @param flag
85     *            the new value for the accessible flag
86     *
87     * @see #setAccessible(boolean)
88     */
89    public static void setAccessible(AccessibleObject[] objects, boolean flag) {
90        synchronized(AccessibleObject.class) {
91            for (AccessibleObject object : objects) {
92                object.flag = flag;
93            }
94        }
95    }
96
97    /**
98     * Constructs a new {@code AccessibleObject} instance. {@code
99     * AccessibleObject} instances can only be constructed by the virtual
100     * machine.
101     */
102    protected AccessibleObject() {
103    }
104
105    /**
106     * Indicates whether this object is accessible without access checks being
107     * performed. Returns the accessible flag.
108     *
109     * @return {@code true} if this object is accessible without access
110     *         checks, {@code false} otherwise
111     */
112    public boolean isAccessible() {
113        return flag;
114    }
115
116    /**
117     * Attempts to set the value of the accessible flag. Setting this flag to
118     * {@code false} will enable access checks, setting to {@code true} will
119     * disable them.
120     *
121     * @param flag
122     *            the new value for the accessible flag
123     */
124    public void setAccessible(boolean flag) {
125        this.flag = flag;
126    }
127
128    public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
129        throw new UnsupportedOperationException();
130    }
131
132    public Annotation[] getDeclaredAnnotations() {
133        throw new UnsupportedOperationException();
134    }
135
136    public Annotation[] getAnnotations() {
137        // for all but Class, getAnnotations == getDeclaredAnnotations
138        return getDeclaredAnnotations();
139    }
140
141    public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
142        throw new UnsupportedOperationException();
143    }
144
145    /**
146     * Returns the signature for a class. This is the kind of signature used
147     * internally by the JVM, with one-character codes representing the basic
148     * types. It is not suitable for printing.
149     *
150     * @param clazz
151     *            the class for which a signature is required
152     *
153     * @return The signature as a string
154     */
155    String getSignature(Class<?> clazz) {
156        String result = "";
157        String nextType = clazz.getName();
158
159        if(trans.containsKey(nextType)) {
160            result = trans.get(nextType);
161        } else {
162            if(clazz.isArray()) {
163                result = "[" + getSignature(clazz.getComponentType());
164            } else {
165                result = "L" + nextType + ";";
166            }
167        }
168        return result;
169    }
170
171    /**
172     * Returns a printable String consisting of the canonical names of the
173     * classes contained in an array. The form is that used in parameter and
174     * exception lists, that is, the class or type names are separated by
175     * commas.
176     *
177     * @param types
178     *            the array of classes
179     *
180     * @return The String of names
181     */
182    String toString(Class<?>[] types) {
183        StringBuilder result = new StringBuilder();
184
185        if (types.length != 0) {
186            appendTypeName(result, types[0]);
187            for (int i = 1; i < types.length; i++) {
188                result.append(',');
189                appendTypeName(result, types[i]);
190            }
191        }
192
193        return result.toString();
194    }
195
196    /**
197     * Gets the Signature attribute for this instance. Returns {@code null}
198     * if not found.
199     */
200    /*package*/ String getSignatureAttribute() {
201        /*
202         * Note: This method would have been declared abstract, but the
203         * standard API lists this class as concrete.
204         */
205        throw new UnsupportedOperationException();
206    }
207
208    /**
209     * Retrieve the signature attribute from an arbitrary class.  This is
210     * the same as Class.getSignatureAttribute(), but it can be used from
211     * the java.lang.reflect package.
212     */
213    /*package*/ static String getClassSignatureAttribute(Class clazz) {
214        Object[] annotation = getClassSignatureAnnotation(clazz);
215
216        if (annotation == null) {
217            return null;
218        }
219
220        return StringUtils.combineStrings(annotation);
221    }
222
223    /**
224     * Retrieve the signature annotation from an arbitrary class.  This is
225     * the same as Class.getSignatureAttribute(), but it can be used from
226     * the java.lang.reflect package.
227     */
228    private static native Object[] getClassSignatureAnnotation(Class clazz);
229
230    /**
231     * Appends the best {@link #toString} name for {@code c} to {@code out}.
232     * This works around the fact that {@link Class#getName} is lousy for
233     * primitive arrays (it writes "[C" instead of "char[]") and {@link
234     * Class#getCanonicalName()} is lousy for nested classes (it uses a "."
235     * separator rather than a "$" separator).
236     */
237    void appendTypeName(StringBuilder out, Class<?> c) {
238        int dimensions = 0;
239        while (c.isArray()) {
240            c = c.getComponentType();
241            dimensions++;
242        }
243        out.append(c.getName());
244        for (int d = 0; d < dimensions; d++) {
245            out.append("[]");
246        }
247    }
248
249    /**
250     * Appends names of the specified array classes to the buffer. The array
251     * elements may represent a simple type, a reference type or an array type.
252     * Output format: java.lang.Object[], java.io.File, void
253     *
254     * @param types array of classes to print the names
255     * @throws NullPointerException if any of the arguments is null
256     */
257    void appendArrayGenericType(StringBuilder sb, Type[] types) {
258        if (types.length > 0) {
259            appendGenericType(sb, types[0]);
260            for (int i = 1; i < types.length; i++) {
261                sb.append(',');
262                appendGenericType(sb, types[i]);
263            }
264        }
265    }
266
267    /**
268     * Appends the generic type representation to the buffer.
269     *
270     * @param sb buffer
271     * @param obj the generic type which representation should be appended to the buffer
272     *
273     * @throws NullPointerException if any of the arguments is null
274     */
275    void appendGenericType(StringBuilder sb, Type obj) {
276        if (obj instanceof TypeVariable) {
277            sb.append(((TypeVariable)obj).getName());
278        } else if (obj instanceof ParameterizedType) {
279            sb.append(obj.toString());
280        } else if (obj instanceof GenericArrayType) { //XXX: is it a working branch?
281            Type simplified = ((GenericArrayType)obj).getGenericComponentType();
282            appendGenericType(sb, simplified);
283            sb.append("[]");
284        } else if (obj instanceof Class) {
285            Class c = ((Class<?>)obj);
286            if (c.isArray()){
287                String as[] = c.getName().split("\\[");
288                int len = as.length-1;
289                if (as[len].length() > 1){
290                    sb.append(as[len].substring(1, as[len].length()-1));
291                } else {
292                    char ch = as[len].charAt(0);
293                    if (ch == 'I')
294                        sb.append("int");
295                    else if (ch == 'B')
296                        sb.append("byte");
297                    else if (ch == 'J')
298                        sb.append("long");
299                    else if (ch == 'F')
300                        sb.append("float");
301                    else if (ch == 'D')
302                        sb.append("double");
303                    else if (ch == 'S')
304                        sb.append("short");
305                    else if (ch == 'C')
306                        sb.append("char");
307                    else if (ch == 'Z')
308                        sb.append("boolean");
309                    else if (ch == 'V') //XXX: is it a working branch?
310                        sb.append("void");
311                }
312                for (int i = 0; i < len; i++){
313                    sb.append("[]");
314                }
315            } else {
316                sb.append(c.getName());
317            }
318        }
319    }
320}
321