blob: 5d9e11c365b24459a9f6fa2b6282d840229db99d [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package java.lang.reflect;
import java.lang.annotation.Annotation;
import java.util.Hashtable;
import org.apache.harmony.kernel.vm.ReflectionAccess;
import org.apache.harmony.kernel.vm.StringUtils;
/**
* {@code AccessibleObject} is the superclass of all member reflection classes
* (Field, Constructor, Method). AccessibleObject provides the ability to toggle
* a flag controlling access checks for these objects. By default, accessing a
* member (for example, setting a field or invoking a method) checks the
* validity of the access (for example, invoking a private method from outside
* the defining class is prohibited) and throws IllegalAccessException if the
* operation is not permitted. If the accessible flag is set to true, these
* checks are omitted. This allows privileged code, such as Java object
* serialization, object inspectors, and debuggers to have complete access to
* objects.
*
* @see Field
* @see Constructor
* @see Method
* @see ReflectPermission
*/
public class AccessibleObject implements AnnotatedElement {
// If true, object is accessible, bypassing normal security checks
boolean flag = false;
/**
* one dimensional array
*/
private static final String DIMENSION_1 = "[]";
/**
* two dimensional array
*/
private static final String DIMENSION_2 = "[][]";
/**
* three dimensional array
*/
private static final String DIMENSION_3 = "[][][]";
// Holds a mapping from Java type names to native type codes.
static Hashtable<String, String> trans;
static {
trans = new Hashtable<String, String>(9);
trans.put("byte", "B");
trans.put("char", "C");
trans.put("short", "S");
trans.put("int", "I");
trans.put("long", "J");
trans.put("float", "F");
trans.put("double", "D");
trans.put("void", "V");
trans.put("boolean", "Z");
}
/**
* Attempts to set the value of the accessible flag for all the objects in
* the array provided. Only one security check is performed. Setting this
* flag to {@code false} will enable access checks, setting to {@code true}
* will disable them. If there is a security manager, checkPermission is
* called with a {@code ReflectPermission("suppressAccessChecks")}.
*
* @param objects
* the accessible objects
* @param flag
* the new value for the accessible flag
*
* @throws SecurityException
* if the request is denied
*
* @see #setAccessible(boolean)
* @see ReflectPermission
*/
public static void setAccessible(AccessibleObject[] objects, boolean flag)
throws SecurityException {
SecurityManager smgr = System.getSecurityManager();
if (smgr != null) {
smgr.checkPermission(new ReflectPermission("suppressAccessChecks"));
}
synchronized(AccessibleObject.class) {
for (int i = 0; i < objects.length; i++) {
objects[i].flag = flag;
}
}
}
/**
* Constructs a new {@code AccessibleObject} instance. {@code
* AccessibleObject} instances can only be constructed by the virtual
* machine.
*/
protected AccessibleObject() {
super();
}
/**
* Indicates whether this object is accessible without security checks being
* performed. Returns the accessible flag.
*
* @return {@code true} if this object is accessible without security
* checks, {@code false} otherwise
*/
public boolean isAccessible() {
return flag;
}
/**
* Attempts to set the value of the accessible flag. Setting this flag to
* {@code false} will enable access checks, setting to {@code true} will
* disable them. If there is a security manager, checkPermission is called
* with a {@code ReflectPermission("suppressAccessChecks")}.
*
* @param flag
* the new value for the accessible flag
*
* @throws SecurityException
* if the request is denied
*
* @see ReflectPermission
*/
public void setAccessible(boolean flag) throws SecurityException {
SecurityManager smgr = System.getSecurityManager();
if (smgr != null) {
smgr.checkPermission(new ReflectPermission("suppressAccessChecks"));
}
this.flag = flag;
}
/**
* Sets the accessible flag on this instance without doing any checks.
*
* @param flag
* the new value for the accessible flag
*/
/*package*/ void setAccessibleNoCheck(boolean flag) {
this.flag = flag;
}
public boolean isAnnotationPresent(Class<? extends Annotation> annotationType) {
return getAnnotation(annotationType) != null;
}
public Annotation[] getDeclaredAnnotations() {
throw new RuntimeException("subclass must override this method");
}
public Annotation[] getAnnotations() {
// for all but Class, getAnnotations == getDeclaredAnnotations
return getDeclaredAnnotations();
}
/* slow, but works for all sub-classes */
public <T extends Annotation> T getAnnotation(Class<T> annotationType) {
if (annotationType == null) {
throw new NullPointerException();
}
Annotation[] annos = getAnnotations();
for (int i = annos.length-1; i >= 0; --i) {
if (annos[i].annotationType() == annotationType) {
return (T) annos[i];
}
}
return null;
}
/**
* Returns the signature for a class. This is the kind of signature used
* internally by the JVM, with one-character codes representing the basic
* types. It is not suitable for printing.
*
* @param clazz
* the class for which a signature is required
*
* @return The signature as a string
*/
String getSignature(Class<?> clazz) {
String result = "";
String nextType = clazz.getName();
if(trans.containsKey(nextType)) {
result = trans.get(nextType);
} else {
if(clazz.isArray()) {
result = "[" + getSignature(clazz.getComponentType());
} else {
result = "L" + nextType + ";";
}
}
return result;
}
/**
* Returns a printable String consisting of the canonical names of the
* classes contained in an array. The form is that used in parameter and
* exception lists, that is, the class or type names are separated by
* commas.
*
* @param types
* the array of classes
*
* @return The String of names
*/
String toString(Class<?>[] types) {
StringBuilder result = new StringBuilder();
if (types.length != 0) {
result.append(types[0].getCanonicalName());
for (int i = 1; i < types.length; i++) {
result.append(',');
result.append(types[i].getCanonicalName());
}
}
return result.toString();
}
/**
* Gets the Signature attribute for this instance. Returns {@code null}
* if not found.
*/
/*package*/ String getSignatureAttribute() {
/*
* Note: This method would have been declared abstract, but the
* standard API lists this class as concrete.
*/
throw new UnsupportedOperationException();
}
/**
* Retrieve the signature attribute from an arbitrary class. This is
* the same as Class.getSignatureAttribute(), but it can be used from
* the java.lang.reflect package.
*/
/*package*/ static String getClassSignatureAttribute(Class clazz) {
Object[] annotation = getClassSignatureAnnotation(clazz);
if (annotation == null) {
return null;
}
return StringUtils.combineStrings(annotation);
}
/**
* Retrieve the signature annotation from an arbitrary class. This is
* the same as Class.getSignatureAttribute(), but it can be used from
* the java.lang.reflect package.
*/
private static native Object[] getClassSignatureAnnotation(Class clazz);
/**
* Gets the unique instance of {@link ReflectionAccessImpl}.
*
* @return non-null; the unique instance
*/
static /*package*/ ReflectionAccess getReflectionAccess() {
return ReflectionAccessImpl.THE_ONE;
}
/**
* Appends the specified class name to the buffer. The class may represent
* a simple type, a reference type or an array type.
*
* @param sb buffer
* @param obj the class which name should be appended to the buffer
*
* @throws NullPointerException if any of the arguments is null
*/
void appendArrayType(StringBuilder sb, Class<?> obj) {
if (!obj.isArray()) {
sb.append(obj.getName());
return;
}
int dimensions = 1;
Class simplified = obj.getComponentType();
obj = simplified;
while (simplified.isArray()) {
obj = simplified;
dimensions++;
}
sb.append(obj.getName());
switch (dimensions) {
case 1:
sb.append(DIMENSION_1);
break;
case 2:
sb.append(DIMENSION_2);
break;
case 3:
sb.append(DIMENSION_3);
break;
default:
for (; dimensions > 0; dimensions--) {
sb.append(DIMENSION_1);
}
}
}
/**
* Appends names of the specified array classes to the buffer. The array
* elements may represent a simple type, a reference type or an array type.
* Output format: java.lang.Object[], java.io.File, void
*
* @param sb buffer
* @param objs array of classes to print the names
*
* @throws NullPointerException if any of the arguments is null
*/
void appendArrayType(StringBuilder sb, Class[] objs) {
if (objs.length > 0) {
appendArrayType(sb, objs[0]);
for (int i = 1; i < objs.length; i++) {
sb.append(',');
appendArrayType(sb, objs[i]);
}
}
}
/**
* Appends names of the specified array classes to the buffer. The array
* elements may represent a simple type, a reference type or an array type.
* Output format: java.lang.Object[], java.io.File, void
*
* @param sb buffer
* @param objs array of classes to print the names
*
* @throws NullPointerException if any of the arguments is null
*/
void appendArrayGenericType(StringBuilder sb, Type[] objs) {
if (objs.length > 0) {
appendGenericType(sb, objs[0]);
for (int i = 1; i < objs.length; i++) {
sb.append(',');
appendGenericType(sb, objs[i]);
}
}
}
/**
* Appends the generic type representation to the buffer.
*
* @param sb buffer
* @param obj the generic type which representation should be appended to the buffer
*
* @throws NullPointerException if any of the arguments is null
*/
void appendGenericType(StringBuilder sb, Type obj) {
if (obj instanceof TypeVariable) {
sb.append(((TypeVariable)obj).getName());
} else if (obj instanceof ParameterizedType) {
sb.append(obj.toString());
} else if (obj instanceof GenericArrayType) { //XXX: is it a working branch?
Type simplified = ((GenericArrayType)obj).getGenericComponentType();
appendGenericType(sb, simplified);
sb.append("[]");
} else if (obj instanceof Class) {
Class c = ((Class<?>)obj);
if (c.isArray()){
String as[] = c.getName().split("\\[");
int len = as.length-1;
if (as[len].length() > 1){
sb.append(as[len].substring(1, as[len].length()-1));
} else {
char ch = as[len].charAt(0);
if (ch == 'I')
sb.append("int");
else if (ch == 'B')
sb.append("byte");
else if (ch == 'J')
sb.append("long");
else if (ch == 'F')
sb.append("float");
else if (ch == 'D')
sb.append("double");
else if (ch == 'S')
sb.append("short");
else if (ch == 'C')
sb.append("char");
else if (ch == 'Z')
sb.append("boolean");
else if (ch == 'V') //XXX: is it a working branch?
sb.append("void");
}
for (int i = 0; i < len; i++){
sb.append("[]");
}
} else {
sb.append(c.getName());
}
}
}
/**
* Appends names of the specified array classes to the buffer. The array
* elements may represent a simple type, a reference type or an array type.
* In case if the specified array element represents an array type its
* internal will be appended to the buffer.
* Output format: [Ljava.lang.Object;, java.io.File, void
*
* @param sb buffer
* @param objs array of classes to print the names
*
* @throws NullPointerException if any of the arguments is null
*/
void appendSimpleType(StringBuilder sb, Class<?>[] objs) {
if (objs.length > 0) {
sb.append(objs[0].getName());
for (int i = 1; i < objs.length; i++) {
sb.append(',');
sb.append(objs[i].getName());
}
}
}
}