1 /* 2 * Copyright (c) 2003, 2013, 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.lang.annotation.*; 29 import java.lang.reflect.*; 30 import java.io.Serializable; 31 import java.util.*; 32 import java.lang.annotation.*; 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 this.type = type; 49 this.memberValues = memberValues; 50 } 51 52 public Object invoke(Object proxy, Method method, Object[] args) { 53 String member = method.getName(); 54 // method names are guaranteed to be interned Strings (see Method.equals()) 55 // so reference compare with string literals (which are interned too) is possible... 56 57 if (member == "equals" && method.getParameterCount() == 1) { 58 assert method.getParameterTypes()[0] == Object.class; 59 return equalsImpl(args[0]); 60 } 61 62 assert method.getParameterCount() == 0; 63 64 if (member == "annotationType") { 65 return type; 66 } 67 68 if (member == "toString") { 69 return toStringImpl(); 70 } 71 72 if (member == "hashCode") { 73 return hashCodeImpl(); 74 } 75 76 // Handle annotation member accessors 77 Object result = memberValues.get(member); 78 if (result == null) { 79 throw new IncompleteAnnotationException(type, member); 80 } 81 if (result instanceof ExceptionProxy) { 82 throw ((ExceptionProxy) result).generateException(); 83 } 84 if (result.getClass().isArray() && Array.getLength(result) != 0) { 85 result = cloneArray(result); 86 } 87 return result; 88 } 89 90 /** 91 * This method, which clones its array argument, would not be necessary 92 * if Cloneable had a public clone method. 93 */ 94 private Object cloneArray(Object array) { 95 Class<?> type = array.getClass(); 96 97 if (type == byte[].class) { 98 byte[] byteArray = (byte[])array; 99 return byteArray.clone(); 100 } 101 if (type == char[].class) { 102 char[] charArray = (char[])array; 103 return charArray.clone(); 104 } 105 if (type == double[].class) { 106 double[] doubleArray = (double[])array; 107 return doubleArray.clone(); 108 } 109 if (type == float[].class) { 110 float[] floatArray = (float[])array; 111 return floatArray.clone(); 112 } 113 if (type == int[].class) { 114 int[] intArray = (int[])array; 115 return intArray.clone(); 116 } 117 if (type == long[].class) { 118 long[] longArray = (long[])array; 119 return longArray.clone(); 120 } 121 if (type == short[].class) { 122 short[] shortArray = (short[])array; 123 return shortArray.clone(); 124 } 125 if (type == boolean[].class) { 126 boolean[] booleanArray = (boolean[])array; 127 return booleanArray.clone(); 128 } 129 130 Object[] objectArray = (Object[])array; 131 return objectArray.clone(); 132 } 133 134 135 /** 136 * Implementation of dynamicProxy.toString() 137 */ 138 private String toStringImpl() { 139 StringBuilder result = new StringBuilder(128); 140 result.append('@'); 141 result.append(type.getName()); 142 result.append('('); 143 boolean firstMember = true; 144 for (Map.Entry<String, Object> e : memberValues.entrySet()) { 145 if (firstMember) 146 firstMember = false; 147 else 148 result.append(", "); 149 150 result.append(e.getKey()); 151 result.append('='); 152 result.append(memberValueToString(e.getValue())); 153 } 154 result.append(')'); 155 return result.toString(); 156 } 157 158 /** 159 * Translates a member value (in "dynamic proxy return form") into a string 160 */ 161 private static String memberValueToString(Object value) { 162 Class<?> type = value.getClass(); 163 if (!type.isArray()) // primitive, string, class, enum const, 164 // or annotation 165 return value.toString(); 166 167 if (type == byte[].class) 168 return Arrays.toString((byte[]) value); 169 if (type == char[].class) 170 return Arrays.toString((char[]) value); 171 if (type == double[].class) 172 return Arrays.toString((double[]) value); 173 if (type == float[].class) 174 return Arrays.toString((float[]) value); 175 if (type == int[].class) 176 return Arrays.toString((int[]) value); 177 if (type == long[].class) 178 return Arrays.toString((long[]) value); 179 if (type == short[].class) 180 return Arrays.toString((short[]) value); 181 if (type == boolean[].class) 182 return Arrays.toString((boolean[]) value); 183 return Arrays.toString((Object[]) value); 184 } 185 186 /** 187 * Implementation of dynamicProxy.equals(Object o) 188 */ 189 private Boolean equalsImpl(Object o) { 190 if (o == this) 191 return true; 192 193 if (!type.isInstance(o)) 194 return false; 195 196 // one of us? 197 AnnotationInvocationHandler hisHandler = asOneOfUs(o); 198 if (hisHandler != null) { // yes 199 for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) { 200 Object ourValue = memberValue.getValue(); 201 Object hisValue = hisHandler.memberValues.get(memberValue.getKey()); 202 if (!memberValueEquals(ourValue, hisValue)) { 203 return false; 204 } 205 } 206 } else { // not one of us 207 for (Map.Entry<String, Method> memberMethod : AnnotationType.getInstance(type).members().entrySet()) { 208 Object ourValue = memberValues.get(memberMethod.getKey()); 209 Object hisValue; 210 try { 211 hisValue = memberMethod.getValue().invoke(o); 212 } catch (InvocationTargetException e) { 213 return false; 214 } catch (IllegalAccessException e) { 215 throw new AssertionError(e); 216 } 217 if (!memberValueEquals(ourValue, hisValue)) { 218 return false; 219 } 220 } 221 } 222 return true; 223 } 224 225 /** 226 * Returns an object's invocation handler if that object is a dynamic 227 * proxy with a handler of type AnnotationInvocationHandler. 228 * Returns null otherwise. 229 */ 230 private static AnnotationInvocationHandler asOneOfUs(Object o) { 231 if (Proxy.isProxyClass(o.getClass())) { 232 InvocationHandler handler = Proxy.getInvocationHandler(o); 233 if (handler instanceof AnnotationInvocationHandler) 234 return (AnnotationInvocationHandler) handler; 235 } 236 return null; 237 } 238 239 /** 240 * Returns true iff the two member values in "dynamic proxy return form" 241 * are equal using the appropriate equality function depending on the 242 * member type. The two values will be of the same type unless one of 243 * the containing annotations is ill-formed. If one of the containing 244 * annotations is ill-formed, this method will return false unless the 245 * two members are identical object references. 246 */ 247 private static boolean memberValueEquals(Object v1, Object v2) { 248 Class<?> type = v1.getClass(); 249 250 // Check for primitive, string, class, enum const, annotation, 251 // or ExceptionProxy 252 if (!type.isArray()) 253 return v1.equals(v2); 254 255 // Check for array of string, class, enum const, annotation, 256 // or ExceptionProxy 257 if (v1 instanceof Object[] && v2 instanceof Object[]) 258 return Arrays.equals((Object[]) v1, (Object[]) v2); 259 260 // Check for ill formed annotation(s) 261 if (v2.getClass() != type) 262 return false; 263 264 // Deal with array of primitives 265 if (type == byte[].class) 266 return Arrays.equals((byte[]) v1, (byte[]) v2); 267 if (type == char[].class) 268 return Arrays.equals((char[]) v1, (char[]) v2); 269 if (type == double[].class) 270 return Arrays.equals((double[]) v1, (double[]) v2); 271 if (type == float[].class) 272 return Arrays.equals((float[]) v1, (float[]) v2); 273 if (type == int[].class) 274 return Arrays.equals((int[]) v1, (int[]) v2); 275 if (type == long[].class) 276 return Arrays.equals((long[]) v1, (long[]) v2); 277 if (type == short[].class) 278 return Arrays.equals((short[]) v1, (short[]) v2); 279 assert type == boolean[].class; 280 return Arrays.equals((boolean[]) v1, (boolean[]) v2); 281 } 282 283 /** 284 * Implementation of dynamicProxy.hashCode() 285 */ 286 private int hashCodeImpl() { 287 int result = 0; 288 for (Map.Entry<String, Object> e : memberValues.entrySet()) { 289 result += (127 * e.getKey().hashCode()) ^ 290 memberValueHashCode(e.getValue()); 291 } 292 return result; 293 } 294 295 /** 296 * Computes hashCode of a member value (in "dynamic proxy return form") 297 */ 298 private static int memberValueHashCode(Object value) { 299 Class<?> type = value.getClass(); 300 if (!type.isArray()) // primitive, string, class, enum const, 301 // or annotation 302 return value.hashCode(); 303 304 if (type == byte[].class) 305 return Arrays.hashCode((byte[]) value); 306 if (type == char[].class) 307 return Arrays.hashCode((char[]) value); 308 if (type == double[].class) 309 return Arrays.hashCode((double[]) value); 310 if (type == float[].class) 311 return Arrays.hashCode((float[]) value); 312 if (type == int[].class) 313 return Arrays.hashCode((int[]) value); 314 if (type == long[].class) 315 return Arrays.hashCode((long[]) value); 316 if (type == short[].class) 317 return Arrays.hashCode((short[]) value); 318 if (type == boolean[].class) 319 return Arrays.hashCode((boolean[]) value); 320 return Arrays.hashCode((Object[]) value); 321 } 322 323 private void readObject(java.io.ObjectInputStream s) 324 throws java.io.IOException, ClassNotFoundException { 325 s.defaultReadObject(); 326 327 328 // Check to make sure that types have not evolved incompatibly 329 330 AnnotationType annotationType = null; 331 try { 332 annotationType = AnnotationType.getInstance(type); 333 } catch(IllegalArgumentException e) { 334 // Class is no longer an annotation type; time to punch out 335 throw new java.io.InvalidObjectException("Non-annotation type in annotation serial stream"); 336 } 337 338 Map<String, Class<?>> memberTypes = annotationType.memberTypes(); 339 340 341 // If there are annotation members without values, that 342 // situation is handled by the invoke method. 343 for (Map.Entry<String, Object> memberValue : memberValues.entrySet()) { 344 String name = memberValue.getKey(); 345 Class<?> memberType = memberTypes.get(name); 346 if (memberType != null) { // i.e. member still exists 347 Object value = memberValue.getValue(); 348 if (!(memberType.isInstance(value) || 349 value instanceof ExceptionProxy)) { 350 memberValue.setValue( 351 new AnnotationTypeMismatchExceptionProxy( 352 value.getClass() + "[" + value + "]").setMember( 353 annotationType.members().get(name))); 354 } 355 } 356 } 357 } 358 359 360 /** 361 * Quick access to member values. If the returned value is an array it might not be a cloned 362 * copy but shared reference, so it must be cloned before exposed to users. 363 * 364 * @param annotation an annotation instance 365 * @param member a member name 366 * @return the value of the member of given annotation or null if no such member exists or 367 * if invoking member method throws exception 368 */ 369 static Object getMemberValue(Annotation annotation, String member) { 370 // one of us? 371 AnnotationInvocationHandler handler = asOneOfUs(annotation); 372 if (handler != null) { // yes 373 return handler.memberValues.get(member); 374 } else { // not one of us 375 Method method = AnnotationType.getInstance(annotation.annotationType()).members().get(member); 376 if (method == null) { 377 return null; 378 } else { 379 try { 380 return method.invoke(annotation); 381 } catch (InvocationTargetException e) { 382 return null; 383 } catch (IllegalAccessException e) { 384 throw new AssertionError(e); 385 } 386 } 387 } 388 } 389 }