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