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 switch(member) { 69 case "toString": 70 return toStringImpl(); 71 case "hashCode": 72 return hashCodeImpl(); 73 case "annotationType": 74 return type; 75 } 76 77 // Handle annotation member accessors 78 Object result = memberValues.get(member); 79 80 if (result == null) 81 throw new IncompleteAnnotationException(type, member); 82 83 if (result instanceof ExceptionProxy) 84 throw ((ExceptionProxy) result).generateException(); 85 86 if (result.getClass().isArray() && Array.getLength(result) != 0) 87 result = cloneArray(result); 88 89 return result; 90 } 91 92 /** 93 * This method, which clones its array argument, would not be necessary 94 * if Cloneable had a public clone method. 95 */ 96 private Object cloneArray(Object array) { 97 Class<?> type = array.getClass(); 98 99 if (type == byte[].class) { 100 byte[] byteArray = (byte[])array; 101 return byteArray.clone(); 102 } 103 if (type == char[].class) { 104 char[] charArray = (char[])array; 105 return charArray.clone(); 106 } 107 if (type == double[].class) { 108 double[] doubleArray = (double[])array; 109 return doubleArray.clone(); 110 } 111 if (type == float[].class) { 112 float[] floatArray = (float[])array; 113 return floatArray.clone(); 114 } 115 if (type == int[].class) { 116 int[] intArray = (int[])array; 117 return intArray.clone(); 118 } 119 if (type == long[].class) { 120 long[] longArray = (long[])array; 121 return longArray.clone(); 122 } 123 if (type == short[].class) { 124 short[] shortArray = (short[])array; 125 return shortArray.clone(); 126 } 127 if (type == boolean[].class) { 128 boolean[] booleanArray = (boolean[])array; 129 return booleanArray.clone(); 130 } 131 132 Object[] objectArray = (Object[])array; 133 return objectArray.clone(); 134 } 135 136 137 /** 138 * Implementation of dynamicProxy.toString() 139 */ 140 private String toStringImpl() { 141 StringBuilder result = new StringBuilder(128); 142 result.append('@'); 143 result.append(type.getName()); 144 result.append('('); 145 boolean firstMember = true; 146 for (Map.Entry<String, Object> e : memberValues.entrySet()) { 147 if (firstMember) 148 firstMember = false; 149 else 150 result.append(", "); 151 152 result.append(e.getKey()); 153 result.append('='); 154 result.append(memberValueToString(e.getValue())); 155 } 156 result.append(')'); 157 return result.toString(); 158 } 159 160 /** 161 * Translates a member value (in "dynamic proxy return form") into a string 162 */ 163 private static String memberValueToString(Object value) { 164 if (value instanceof ExceptionProxy) { 165 return ((ExceptionProxy)value).memberToString(); 166 } 167 Class<?> type = value.getClass(); 168 if (!type.isArray()) // primitive, string, class, enum const, 169 // or annotation 170 return value.toString(); 171 172 if (type == byte[].class) 173 return Arrays.toString((byte[]) value); 174 if (type == char[].class) 175 return Arrays.toString((char[]) value); 176 if (type == double[].class) 177 return Arrays.toString((double[]) value); 178 if (type == float[].class) 179 return Arrays.toString((float[]) value); 180 if (type == int[].class) 181 return Arrays.toString((int[]) value); 182 if (type == long[].class) 183 return Arrays.toString((long[]) value); 184 if (type == short[].class) 185 return Arrays.toString((short[]) value); 186 if (type == boolean[].class) 187 return Arrays.toString((boolean[]) value); 188 return Arrays.toString((Object[]) value); 189 } 190 191 /** 192 * Implementation of dynamicProxy.equals(Object o) 193 */ 194 private Boolean equalsImpl(Object o) { 195 if (o == this) 196 return true; 197 198 if (!type.isInstance(o)) 199 return false; 200 for (Method memberMethod : getMemberMethods()) { 201 String member = memberMethod.getName(); 202 Object ourValue = memberValues.get(member); 203 Object hisValue = null; 204 AnnotationInvocationHandler hisHandler = asOneOfUs(o); 205 if (hisHandler != null) { 206 hisValue = hisHandler.memberValues.get(member); 207 } else { 208 try { 209 hisValue = memberMethod.invoke(o); 210 } catch (InvocationTargetException e) { 211 return false; 212 } catch (IllegalAccessException e) { 213 throw new AssertionError(e); 214 } 215 } 216 if (!memberValueEquals(ourValue, hisValue)) 217 return false; 218 } 219 return true; 220 } 221 222 /** 223 * Returns an object's invocation handler if that object is a dynamic 224 * proxy with a handler of type AnnotationInvocationHandler. 225 * Returns null otherwise. 226 */ 227 private AnnotationInvocationHandler asOneOfUs(Object o) { 228 if (Proxy.isProxyClass(o.getClass())) { 229 InvocationHandler handler = Proxy.getInvocationHandler(o); 230 if (handler instanceof AnnotationInvocationHandler) 231 return (AnnotationInvocationHandler) handler; 232 } 233 return null; 234 } 235 236 /** 237 * Returns true iff the two member values in "dynamic proxy return form" 238 * are equal using the appropriate equality function depending on the 239 * member type. The two values will be of the same type unless one of 240 * the containing annotations is ill-formed. If one of the containing 241 * annotations is ill-formed, this method will return false unless the 242 * two members are identical object references. 243 */ 244 private static boolean memberValueEquals(Object v1, Object v2) { 245 Class<?> type = v1.getClass(); 246 247 // Check for primitive, string, class, enum const, annotation, 248 // or ExceptionProxy 249 if (!type.isArray()) 250 return v1.equals(v2); 251 252 // Check for array of string, class, enum const, annotation, 253 // or ExceptionProxy 254 if (v1 instanceof Object[] && v2 instanceof Object[]) 255 return Arrays.equals((Object[]) v1, (Object[]) v2); 256 257 // Check for ill formed annotation(s) 258 if (v2.getClass() != type) 259 return false; 260 261 // Deal with array of primitives 262 if (type == byte[].class) 263 return Arrays.equals((byte[]) v1, (byte[]) v2); 264 if (type == char[].class) 265 return Arrays.equals((char[]) v1, (char[]) v2); 266 if (type == double[].class) 267 return Arrays.equals((double[]) v1, (double[]) v2); 268 if (type == float[].class) 269 return Arrays.equals((float[]) v1, (float[]) v2); 270 if (type == int[].class) 271 return Arrays.equals((int[]) v1, (int[]) v2); 272 if (type == long[].class) 273 return Arrays.equals((long[]) v1, (long[]) v2); 274 if (type == short[].class) 275 return Arrays.equals((short[]) v1, (short[]) v2); 276 assert type == boolean[].class; 277 return Arrays.equals((boolean[]) v1, (boolean[]) v2); 278 } 279 280 /** 281 * Returns the member methods for our annotation type. These are 282 * obtained lazily and cached, as they're expensive to obtain 283 * and we only need them if our equals method is invoked (which should 284 * be rare). 285 */ 286 private Method[] getMemberMethods() { 287 Method[] value = memberMethods; 288 if (value == null) { 289 value = computeMemberMethods(); 290 memberMethods = value; 291 } 292 return value; 293 } 294 295 private Method[] computeMemberMethods() { 296 return AccessController.doPrivileged( 297 new PrivilegedAction<Method[]>() { 298 public Method[] run() { 299 final Method[] methods = type.getDeclaredMethods(); 300 validateAnnotationMethods(methods); 301 AccessibleObject.setAccessible(methods, true); 302 return methods; 303 }}); 304 } 305 306 private transient volatile Method[] memberMethods; 307 308 /** 309 * Validates that a method is structurally appropriate for an 310 * annotation type. As of Java SE 8, annotation types cannot 311 * contain static methods and the declared methods of an 312 * annotation type must take zero arguments and there are 313 * restrictions on the return type. 314 */ 315 private void validateAnnotationMethods(Method[] memberMethods) { 316 /* 317 * Specification citations below are from JLS 318 * 9.6.1. Annotation Type Elements 319 */ 320 boolean valid = true; 321 for(Method method : memberMethods) { 322 /* 323 * "By virtue of the AnnotationTypeElementDeclaration 324 * production, a method declaration in an annotation type 325 * declaration cannot have formal parameters, type 326 * parameters, or a throws clause. 327 * 328 * "By virtue of the AnnotationTypeElementModifier 329 * production, a method declaration in an annotation type 330 * declaration cannot be default or static." 331 */ 332 if (method.getModifiers() != (Modifier.PUBLIC | Modifier.ABSTRACT) || 333 method.isDefault() || 334 method.getParameterCount() != 0 || 335 method.getExceptionTypes().length != 0) { 336 valid = false; 337 break; 338 } 339 340 /* 341 * "It is a compile-time error if the return type of a 342 * method declared in an annotation type is not one of the 343 * following: a primitive type, String, Class, any 344 * parameterized invocation of Class, an enum type 345 * (section 8.9), an annotation type, or an array type 346 * (chapter 10) whose element type is one of the preceding 347 * types." 348 */ 349 Class<?> returnType = method.getReturnType(); 350 if (returnType.isArray()) { 351 returnType = returnType.getComponentType(); 352 if (returnType.isArray()) { // Only single dimensional arrays 353 valid = false; 354 break; 355 } 356 } 357 358 if (!((returnType.isPrimitive() && returnType != void.class) || 359 returnType == java.lang.String.class || 360 returnType == java.lang.Class.class || 361 returnType.isEnum() || 362 returnType.isAnnotation())) { 363 valid = false; 364 break; 365 } 366 367 /* 368 * "It is a compile-time error if any method declared in an 369 * annotation type has a signature that is 370 * override-equivalent to that of any public or protected 371 * method declared in class Object or in the interface 372 * java.lang.annotation.Annotation." 373 * 374 * The methods in Object or Annotation meeting the other 375 * criteria (no arguments, contrained return type, etc.) 376 * above are: 377 * 378 * String toString() 379 * int hashCode() 380 * Class<? extends Annotation> annotationType() 381 */ 382 String methodName = method.getName(); 383 if ((methodName.equals("toString") && returnType == java.lang.String.class) || 384 (methodName.equals("hashCode") && returnType == int.class) || 385 (methodName.equals("annotationType") && returnType == java.lang.Class.class)) { 386 valid = false; 387 break; 388 } 389 } 390 if (valid) 391 return; 392 else 393 throw new AnnotationFormatError("Malformed method on an annotation type"); 394 } 395 396 /** 397 * Implementation of dynamicProxy.hashCode() 398 */ 399 private int hashCodeImpl() { 400 int result = 0; 401 for (Map.Entry<String, Object> e : memberValues.entrySet()) { 402 result += (127 * e.getKey().hashCode()) ^ 403 memberValueHashCode(e.getValue()); 404 } 405 return result; 406 } 407 408 /** 409 * Computes hashCode of a member value (in "dynamic proxy return form") 410 */ 411 private static int memberValueHashCode(Object value) { 412 Class<?> type = value.getClass(); 413 if (!type.isArray()) // primitive, string, class, enum const, 414 // or annotation 415 return value.hashCode(); 416 417 if (type == byte[].class) 418 return Arrays.hashCode((byte[]) value); 419 if (type == char[].class) 420 return Arrays.hashCode((char[]) value); 421 if (type == double[].class) 422 return Arrays.hashCode((double[]) value); 423 if (type == float[].class) 424 return Arrays.hashCode((float[]) value); 425 if (type == int[].class) 426 return Arrays.hashCode((int[]) value); 427 if (type == long[].class) 428 return Arrays.hashCode((long[]) value); 429 if (type == short[].class) 430 return Arrays.hashCode((short[]) value); 431 if (type == boolean[].class) 432 return Arrays.hashCode((boolean[]) value); 433 return Arrays.hashCode((Object[]) value); 434 } 435 436 private void readObject(java.io.ObjectInputStream s) 437 throws java.io.IOException, ClassNotFoundException { 438 ObjectInputStream.GetField fields = s.readFields(); 439 440 @SuppressWarnings("unchecked") 441 Class<? extends Annotation> t = (Class<? extends Annotation>)fields.get("type", null); 442 @SuppressWarnings("unchecked") 443 Map<String, Object> streamVals = (Map<String, Object>)fields.get("memberValues", null); 444 445 // Check to make sure that types have not evolved incompatibly 446 447 AnnotationType annotationType = null; 448 try { 449 annotationType = AnnotationType.getInstance(t); 450 } catch(IllegalArgumentException e) { 451 // Class is no longer an annotation type; time to punch out 452 throw new java.io.InvalidObjectException("Non-annotation type in annotation serial stream"); 453 } 454 455 Map<String, Class<?>> memberTypes = annotationType.memberTypes(); 456 // consistent with runtime Map type 457 Map<String, Object> mv = new LinkedHashMap<>(); 458 459 // If there are annotation members without values, that 460 // situation is handled by the invoke method. 461 for (Map.Entry<String, Object> memberValue : streamVals.entrySet()) { 462 String name = memberValue.getKey(); 463 Object value = null; 464 Class<?> memberType = memberTypes.get(name); 465 if (memberType != null) { // i.e. member still exists 466 value = memberValue.getValue(); 467 if (!(memberType.isInstance(value) || 468 value instanceof ExceptionProxy)) { 469 value = new AnnotationTypeMismatchExceptionProxy( 470 value.getClass() + "[" + value + "]").setMember( 471 annotationType.members().get(name)); 472 } 473 } 474 mv.put(name, value); 475 } 476 477 UnsafeAccessor.setType(this, t); 478 UnsafeAccessor.setMemberValues(this, mv); 479 } 480 481 private static class UnsafeAccessor { 482 private static final jdk.internal.misc.Unsafe unsafe; 483 private static final long typeOffset; 484 private static final long memberValuesOffset; 485 static { 486 try { 487 unsafe = jdk.internal.misc.Unsafe.getUnsafe(); 488 typeOffset = unsafe.objectFieldOffset 489 (AnnotationInvocationHandler.class.getDeclaredField("type")); 490 memberValuesOffset = unsafe.objectFieldOffset 491 (AnnotationInvocationHandler.class.getDeclaredField("memberValues")); 492 } catch (Exception ex) { 493 throw new ExceptionInInitializerError(ex); 494 } 495 } 496 static void setType(AnnotationInvocationHandler o, 497 Class<? extends Annotation> type) { 498 unsafe.putObject(o, typeOffset, type); 499 } 500 501 static void setMemberValues(AnnotationInvocationHandler o, 502 Map<String, Object> memberValues) { 503 unsafe.putObject(o, memberValuesOffset, memberValues); 504 } 505 } 506 }