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 }