1 /* 2 * Copyright (c) 2003, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package sun.reflect.annotation; 27 28 import java.io.ObjectInputStream; 29 import java.lang.annotation.*; 30 import java.lang.reflect.*; 31 import java.io.Serializable; 32 import java.util.*; 33 import java.security.AccessController; 34 import java.security.PrivilegedAction; 35 36 /** 37 * InvocationHandler for dynamic proxy implementation of Annotation. 38 * 39 * @author Josh Bloch 40 * @since 1.5 41 */ 42 class AnnotationInvocationHandler implements InvocationHandler, Serializable { 43 private static final long serialVersionUID = 6182022883658399397L; 44 private final Class<? extends Annotation> type; 45 private final Map<String, Object> memberValues; 46 47 AnnotationInvocationHandler(Class<? extends Annotation> type, Map<String, Object> memberValues) { 48 Class<?>[] superInterfaces = type.getInterfaces(); 49 if (!type.isAnnotation() || 50 superInterfaces.length != 1 || 51 superInterfaces[0] != java.lang.annotation.Annotation.class) 52 throw new AnnotationFormatError("Attempt to create proxy for a non-annotation type."); 53 this.type = type; 54 this.memberValues = memberValues; 55 } 56 57 public Object invoke(Object proxy, Method method, Object[] args) { 58 String member = method.getName(); 59 Class<?>[] paramTypes = method.getParameterTypes(); 60 61 // Handle Object and Annotation methods 62 if (member.equals("equals") && paramTypes.length == 1 && 63 paramTypes[0] == Object.class) 64 return equalsImpl(args[0]); 65 if (paramTypes.length != 0) 66 throw new AssertionError("Too many parameters for an annotation method"); 67 68 if ("toString".equals(member)) { 69 return toStringImpl(); 70 } else if ("hashCode".equals(member)) { 71 return hashCodeImpl(); 72 } else if ("annotationType".equals(member)) { 73 return type; 74 } 75 76 // Handle annotation member accessors 77 Object result = memberValues.get(member); 78 79 if (result == null) 80 throw new IncompleteAnnotationException(type, member); 81 82 if (result instanceof ExceptionProxy) 83 throw ((ExceptionProxy) result).generateException(); 84 85 if (result.getClass().isArray() && Array.getLength(result) != 0) 86 result = cloneArray(result); 87 88 return result; 89 } 90 91 /** 92 * This method, which clones its array argument, would not be necessary 93 * if Cloneable had a public clone method. 94 */ 95 private Object cloneArray(Object array) { 96 Class<?> type = array.getClass(); 97 98 if (type == byte[].class) { 99 byte[] byteArray = (byte[])array; 100 return byteArray.clone(); 101 } 102 if (type == char[].class) { 103 char[] charArray = (char[])array; 104 return charArray.clone(); 105 } 106 if (type == double[].class) { 107 double[] doubleArray = (double[])array; 108 return doubleArray.clone(); 109 } 110 if (type == float[].class) { 111 float[] floatArray = (float[])array; 112 return floatArray.clone(); 113 } 114 if (type == int[].class) { 115 int[] intArray = (int[])array; 116 return intArray.clone(); 117 } 118 if (type == long[].class) { 119 long[] longArray = (long[])array; 120 return longArray.clone(); 121 } 122 if (type == short[].class) { 123 short[] shortArray = (short[])array; 124 return shortArray.clone(); 125 } 126 if (type == boolean[].class) { 127 boolean[] booleanArray = (boolean[])array; 128 return booleanArray.clone(); 129 } 130 131 Object[] objectArray = (Object[])array; 132 return objectArray.clone(); 133 } 134 135 136 /** 137 * Implementation of dynamicProxy.toString() 138 */ 139 private String toStringImpl() { 140 StringBuilder result = new StringBuilder(128); 141 result.append('@'); 142 result.append(type.getName()); 143 result.append('('); 144 boolean firstMember = true; 145 for (Map.Entry<String, Object> e : memberValues.entrySet()) { 146 if (firstMember) 147 firstMember = false; 148 else 149 result.append(", "); 150 151 result.append(e.getKey()); 152 result.append('='); 153 result.append(memberValueToString(e.getValue())); 154 } 155 result.append(')'); 156 return result.toString(); 157 } 158 159 /** 160 * Translates a member value (in "dynamic proxy return form") into a string 161 */ 162 private static String memberValueToString(Object value) { 163 Class<?> type = value.getClass(); 164 if (!type.isArray()) // primitive, string, class, enum const, 165 // or annotation 166 return value.toString(); 167 168 if (type == byte[].class) 169 return Arrays.toString((byte[]) value); 170 if (type == char[].class) 171 return Arrays.toString((char[]) value); 172 if (type == double[].class) 173 return Arrays.toString((double[]) value); 174 if (type == float[].class) 175 return Arrays.toString((float[]) value); 176 if (type == int[].class) 177 return Arrays.toString((int[]) value); 178 if (type == long[].class) 179 return Arrays.toString((long[]) value); 180 if (type == short[].class) 181 return Arrays.toString((short[]) value); 182 if (type == boolean[].class) 183 return Arrays.toString((boolean[]) value); 184 return Arrays.toString((Object[]) value); 185 } 186 187 /** 188 * Implementation of dynamicProxy.equals(Object o) 189 */ 190 private Boolean equalsImpl(Object o) { 191 if (o == this) 192 return true; 193 194 if (!type.isInstance(o)) 195 return false; 196 for (Method memberMethod : getMemberMethods()) { 197 String member = memberMethod.getName(); 198 Object ourValue = memberValues.get(member); 199 Object hisValue = null; 200 AnnotationInvocationHandler hisHandler = asOneOfUs(o); 201 if (hisHandler != null) { 202 hisValue = hisHandler.memberValues.get(member); 203 } else { 204 try { 205 hisValue = memberMethod.invoke(o); 206 } catch (InvocationTargetException e) { 207 return false; 208 } catch (IllegalAccessException e) { 209 throw new AssertionError(e); 210 } 211 } 212 if (!memberValueEquals(ourValue, hisValue)) 213 return false; 214 } 215 return true; 216 } 217 218 /** 219 * Returns an object's invocation handler if that object is a dynamic 220 * proxy with a handler of type AnnotationInvocationHandler. 221 * Returns null otherwise. 222 */ 223 private AnnotationInvocationHandler asOneOfUs(Object o) { 224 if (Proxy.isProxyClass(o.getClass())) { 225 InvocationHandler handler = Proxy.getInvocationHandler(o); 226 if (handler instanceof AnnotationInvocationHandler) 227 return (AnnotationInvocationHandler) handler; 228 } 229 return null; 230 } 231 232 /** 233 * Returns true iff the two member values in "dynamic proxy return form" 234 * are equal using the appropriate equality function depending on the 235 * member type. The two values will be of the same type unless one of 236 * the containing annotations is ill-formed. If one of the containing 237 * annotations is ill-formed, this method will return false unless the 238 * two members are identical object references. 239 */ 240 private static boolean memberValueEquals(Object v1, Object v2) { 241 Class<?> type = v1.getClass(); 242 243 // Check for primitive, string, class, enum const, annotation, 244 // or ExceptionProxy 245 if (!type.isArray()) 246 return v1.equals(v2); 247 248 // Check for array of string, class, enum const, annotation, 249 // or ExceptionProxy 250 if (v1 instanceof Object[] && v2 instanceof Object[]) 251 return Arrays.equals((Object[]) v1, (Object[]) v2); 252 253 // Check for ill formed annotation(s) 254 if (v2.getClass() != type) 255 return false; 256 257 // Deal with array of primitives 258 if (type == byte[].class) 259 return Arrays.equals((byte[]) v1, (byte[]) v2); 260 if (type == char[].class) 261 return Arrays.equals((char[]) v1, (char[]) v2); 262 if (type == double[].class) 263 return Arrays.equals((double[]) v1, (double[]) v2); 264 if (type == float[].class) 265 return Arrays.equals((float[]) v1, (float[]) v2); 266 if (type == int[].class) 267 return Arrays.equals((int[]) v1, (int[]) v2); 268 if (type == long[].class) 269 return Arrays.equals((long[]) v1, (long[]) v2); 270 if (type == short[].class) 271 return Arrays.equals((short[]) v1, (short[]) v2); 272 assert type == boolean[].class; 273 return Arrays.equals((boolean[]) v1, (boolean[]) v2); 274 } 275 276 /** 277 * Returns the member methods for our annotation type. These are 278 * obtained lazily and cached, as they're expensive to obtain 279 * and we only need them if our equals method is invoked (which should 280 * be rare). 281 */ 282 private Method[] getMemberMethods() { 283 if (memberMethods == null) { 284 memberMethods = AccessController.doPrivileged( 285 new PrivilegedAction<Method[]>() { 286 public Method[] run() { 287 final Method[] mm = type.getDeclaredMethods(); 288 validateAnnotationMethods(mm); 289 AccessibleObject.setAccessible(mm, true); 290 return mm; 291 } 292 }); 293 } 294 return memberMethods; 295 } 296 private transient volatile Method[] memberMethods = null; 297 298 /** 299 * Validates that a method is structurally appropriate for an 300 * annotation type. As of Java SE 6, annotation types cannot 301 * contain static methods and the declared methods of an 302 * annotation type must take zero arguments and there are 303 * restrictions on the return type. 304 */ 305 private void validateAnnotationMethods(Method[] memberMethods) { 306 /* 307 * Specification citations below are from JLS 308 * 9.6. Annotation Types 309 */ 310 boolean valid = true; 311 for(Method method : memberMethods) { 312 /* 313 * "By virtue of the AnnotationTypeElementDeclaration 314 * production, a method declaration in an annotation type 315 * declaration cannot have formal parameters, type 316 * parameters, or a throws clause. 317 * 318 * "By virtue of the AbstractMethodModifier 319 * production, a method declaration in an annotation type 320 * declaration cannot be default or static." 321 */ 322 if (method.getModifiers() != (Modifier.PUBLIC | Modifier.ABSTRACT) || 323 method.getParameterTypes().length != 0 || 324 method.getExceptionTypes().length != 0) { 325 valid = false; 326 break; 327 } 328 329 /* 330 * "It is a compile-time error if the return type of a 331 * method declared in an annotation type is not one of the 332 * following: a primitive type, String, Class, any 333 * parameterized invocation of Class, an enum type 334 * (section 8.9), an annotation type, or an array type 335 * (chapter 10) whose element type is one of the preceding 336 * types." 337 */ 338 Class<?> returnType = method.getReturnType(); 339 if (returnType.isArray()) { 340 returnType = returnType.getComponentType(); 341 if (returnType.isArray()) { // Only single dimensional arrays 342 valid = false; 343 break; 344 } 345 } 346 347 if (!((returnType.isPrimitive() && returnType != void.class) || 348 returnType == java.lang.String.class || 349 returnType == java.lang.Class.class || 350 returnType.isEnum() || 351 returnType.isAnnotation())) { 352 valid = false; 353 break; 354 } 355 356 /* 357 * "It is a compile-time error if any method declared in an 358 * annotation type has a signature that is 359 * override-equivalent to that of any public or protected 360 * method declared in class Object or in the interface 361 * java.lang.annotation.Annotation." 362 * 363 * The methods in Object or Annotation meeting the other 364 * criteria (no arguments, constrained return type, etc.) 365 * above are: 366 * 367 * String toString() 368 * int hashCode() 369 * Class<? extends Annotation> annotationType() 370 */ 371 String methodName = method.getName(); 372 if ((methodName.equals("toString") && returnType == java.lang.String.class) || 373 (methodName.equals("hashCode") && returnType == int.class) || 374 (methodName.equals("annotationType") && returnType == java.lang.Class.class)) { 375 valid = false; 376 break; 377 } 378 } 379 if (valid) 380 return; 381 else 382 throw new AnnotationFormatError("Malformed method on an annotation type"); 383 } 384 385 /** 386 * Implementation of dynamicProxy.hashCode() 387 */ 388 private int hashCodeImpl() { 389 int result = 0; 390 for (Map.Entry<String, Object> e : memberValues.entrySet()) { 391 result += (127 * e.getKey().hashCode()) ^ 392 memberValueHashCode(e.getValue()); 393 } 394 return result; 395 } 396 397 /** 398 * Computes hashCode of a member value (in "dynamic proxy return form") 399 */ 400 private static int memberValueHashCode(Object value) { 401 Class<?> type = value.getClass(); 402 if (!type.isArray()) // primitive, string, class, enum const, 403 // or annotation 404 return value.hashCode(); 405 406 if (type == byte[].class) 407 return Arrays.hashCode((byte[]) value); 408 if (type == char[].class) 409 return Arrays.hashCode((char[]) value); 410 if (type == double[].class) 411 return Arrays.hashCode((double[]) value); 412 if (type == float[].class) 413 return Arrays.hashCode((float[]) value); 414 if (type == int[].class) 415 return Arrays.hashCode((int[]) value); 416 if (type == long[].class) 417 return Arrays.hashCode((long[]) value); 418 if (type == short[].class) 419 return Arrays.hashCode((short[]) value); 420 if (type == boolean[].class) 421 return Arrays.hashCode((boolean[]) value); 422 return Arrays.hashCode((Object[]) value); 423 } 424 425 private void readObject(java.io.ObjectInputStream s) 426 throws java.io.IOException, ClassNotFoundException { 427 ObjectInputStream.GetField fields = s.readFields(); 428 429 @SuppressWarnings("unchecked") 430 Class<? extends Annotation> t = (Class<? extends Annotation>)fields.get("type", null); 431 @SuppressWarnings("unchecked") 432 Map<String, Object> streamVals = (Map<String, Object>)fields.get("memberValues", null); 433 434 // Check to make sure that types have not evolved incompatibly 435 436 AnnotationType annotationType = null; 437 try { 438 annotationType = AnnotationType.getInstance(t); 439 } catch(IllegalArgumentException e) { 440 // Class is no longer an annotation type; time to punch out 441 throw new java.io.InvalidObjectException("Non-annotation type in annotation serial stream"); 442 } 443 444 Map<String, Class<?>> memberTypes = annotationType.memberTypes(); 445 // consistent with runtime Map type 446 Map<String, Object> mv = new LinkedHashMap<String, Object>(); 447 448 // If there are annotation members without values, that 449 // situation is handled by the invoke method. 450 for (Map.Entry<String, Object> memberValue : streamVals.entrySet()) { 451 String name = memberValue.getKey(); 452 Object value = null; 453 Class<?> memberType = memberTypes.get(name); 454 if (memberType != null) { // i.e. member still exists 455 value = memberValue.getValue(); 456 if (!(memberType.isInstance(value) || 457 value instanceof ExceptionProxy)) { 458 value = new AnnotationTypeMismatchExceptionProxy( 459 value.getClass() + "[" + value + "]").setMember( 460 annotationType.members().get(name)); 461 } 462 } 463 mv.put(name, value); 464 } 465 466 UnsafeAccessor.setType(this, t); 467 UnsafeAccessor.setMemberValues(this, mv); 468 } 469 470 private static class UnsafeAccessor { 471 private static final sun.misc.Unsafe unsafe; 472 private static final long typeOffset; 473 private static final long memberValuesOffset; 474 static { 475 try { 476 unsafe = sun.misc.Unsafe.getUnsafe(); 477 typeOffset = unsafe.objectFieldOffset 478 (AnnotationInvocationHandler.class.getDeclaredField("type")); 479 memberValuesOffset = unsafe.objectFieldOffset 480 (AnnotationInvocationHandler.class.getDeclaredField("memberValues")); 481 } catch (Exception ex) { 482 throw new ExceptionInInitializerError(ex); 483 } 484 } 485 static void setType(AnnotationInvocationHandler o, 486 Class<? extends Annotation> type) { 487 unsafe.putObject(o, typeOffset, type); 488 } 489 490 static void setMemberValues(AnnotationInvocationHandler o, 491 Map<String, Object> memberValues) { 492 unsafe.putObject(o, memberValuesOffset, memberValues); 493 } 494 } 495 }