src/java.base/share/classes/sun/reflect/annotation/AnnotationInvocationHandler.java
changeset 47216 71c04702a3d5
parent 46873 7ac2f551b0d6
child 47436 389695e5e8db
equal deleted inserted replaced
47215:4ebc2e2fb97c 47216:71c04702a3d5
       
     1 /*
       
     2  * Copyright (c) 2003, 2016, 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.util.stream.*;
       
    34 import java.security.AccessController;
       
    35 import java.security.PrivilegedAction;
       
    36 
       
    37 /**
       
    38  * InvocationHandler for dynamic proxy implementation of Annotation.
       
    39  *
       
    40  * @author  Josh Bloch
       
    41  * @since   1.5
       
    42  */
       
    43 class AnnotationInvocationHandler implements InvocationHandler, Serializable {
       
    44     private static final long serialVersionUID = 6182022883658399397L;
       
    45     private final Class<? extends Annotation> type;
       
    46     private final Map<String, Object> memberValues;
       
    47 
       
    48     AnnotationInvocationHandler(Class<? extends Annotation> type, Map<String, Object> memberValues) {
       
    49         Class<?>[] superInterfaces = type.getInterfaces();
       
    50         if (!type.isAnnotation() ||
       
    51             superInterfaces.length != 1 ||
       
    52             superInterfaces[0] != java.lang.annotation.Annotation.class)
       
    53             throw new AnnotationFormatError("Attempt to create proxy for a non-annotation type.");
       
    54         this.type = type;
       
    55         this.memberValues = memberValues;
       
    56     }
       
    57 
       
    58     public Object invoke(Object proxy, Method method, Object[] args) {
       
    59         String member = method.getName();
       
    60         Class<?>[] paramTypes = method.getParameterTypes();
       
    61 
       
    62         // Handle Object and Annotation methods
       
    63         if (member.equals("equals") && paramTypes.length == 1 &&
       
    64             paramTypes[0] == Object.class)
       
    65             return equalsImpl(proxy, args[0]);
       
    66         if (paramTypes.length != 0)
       
    67             throw new AssertionError("Too many parameters for an annotation method");
       
    68 
       
    69         switch(member) {
       
    70         case "toString":
       
    71             return toStringImpl();
       
    72         case "hashCode":
       
    73             return hashCodeImpl();
       
    74         case "annotationType":
       
    75             return type;
       
    76         }
       
    77 
       
    78         // Handle annotation member accessors
       
    79         Object result = memberValues.get(member);
       
    80 
       
    81         if (result == null)
       
    82             throw new IncompleteAnnotationException(type, member);
       
    83 
       
    84         if (result instanceof ExceptionProxy)
       
    85             throw ((ExceptionProxy) result).generateException();
       
    86 
       
    87         if (result.getClass().isArray() && Array.getLength(result) != 0)
       
    88             result = cloneArray(result);
       
    89 
       
    90         return result;
       
    91     }
       
    92 
       
    93     /**
       
    94      * This method, which clones its array argument, would not be necessary
       
    95      * if Cloneable had a public clone method.
       
    96      */
       
    97     private Object cloneArray(Object array) {
       
    98         Class<?> type = array.getClass();
       
    99 
       
   100         if (type == byte[].class) {
       
   101             byte[] byteArray = (byte[])array;
       
   102             return byteArray.clone();
       
   103         }
       
   104         if (type == char[].class) {
       
   105             char[] charArray = (char[])array;
       
   106             return charArray.clone();
       
   107         }
       
   108         if (type == double[].class) {
       
   109             double[] doubleArray = (double[])array;
       
   110             return doubleArray.clone();
       
   111         }
       
   112         if (type == float[].class) {
       
   113             float[] floatArray = (float[])array;
       
   114             return floatArray.clone();
       
   115         }
       
   116         if (type == int[].class) {
       
   117             int[] intArray = (int[])array;
       
   118             return intArray.clone();
       
   119         }
       
   120         if (type == long[].class) {
       
   121             long[] longArray = (long[])array;
       
   122             return longArray.clone();
       
   123         }
       
   124         if (type == short[].class) {
       
   125             short[] shortArray = (short[])array;
       
   126             return shortArray.clone();
       
   127         }
       
   128         if (type == boolean[].class) {
       
   129             boolean[] booleanArray = (boolean[])array;
       
   130             return booleanArray.clone();
       
   131         }
       
   132 
       
   133         Object[] objectArray = (Object[])array;
       
   134         return objectArray.clone();
       
   135     }
       
   136 
       
   137 
       
   138     /**
       
   139      * Implementation of dynamicProxy.toString()
       
   140      */
       
   141     private String toStringImpl() {
       
   142         StringBuilder result = new StringBuilder(128);
       
   143         result.append('@');
       
   144         result.append(type.getName());
       
   145         result.append('(');
       
   146         boolean firstMember = true;
       
   147         for (Map.Entry<String, Object> e : memberValues.entrySet()) {
       
   148             if (firstMember)
       
   149                 firstMember = false;
       
   150             else
       
   151                 result.append(", ");
       
   152 
       
   153             result.append(e.getKey());
       
   154             result.append('=');
       
   155             result.append(memberValueToString(e.getValue()));
       
   156         }
       
   157         result.append(')');
       
   158         return result.toString();
       
   159     }
       
   160 
       
   161     /**
       
   162      * Translates a member value (in "dynamic proxy return form") into a string.
       
   163      */
       
   164     private static String memberValueToString(Object value) {
       
   165         Class<?> type = value.getClass();
       
   166         if (!type.isArray()) {
       
   167             // primitive value, string, class, enum const, or annotation
       
   168             if (type == Class.class)
       
   169                 return toSourceString((Class<?>) value);
       
   170             else if (type == String.class)
       
   171                 return  toSourceString((String) value);
       
   172             if (type == Character.class)
       
   173                 return toSourceString((char) value);
       
   174             else if (type == Double.class)
       
   175                 return  toSourceString((double) value);
       
   176             else if (type == Float.class)
       
   177                 return  toSourceString((float) value);
       
   178             else if (type == Long.class)
       
   179                 return  toSourceString((long) value);
       
   180             else
       
   181                 return value.toString();
       
   182         } else {
       
   183             Stream<String> stringStream;
       
   184             if (type == byte[].class)
       
   185                 stringStream = convert((byte[]) value);
       
   186             else if (type == char[].class)
       
   187                 stringStream = convert((char[]) value);
       
   188             else if (type == double[].class)
       
   189                 stringStream = DoubleStream.of((double[]) value)
       
   190                     .mapToObj(AnnotationInvocationHandler::toSourceString);
       
   191             else if (type == float[].class)
       
   192                 stringStream = convert((float[]) value);
       
   193             else if (type == int[].class)
       
   194                 stringStream = IntStream.of((int[]) value).mapToObj(String::valueOf);
       
   195             else if (type == long[].class) {
       
   196                 stringStream = LongStream.of((long[]) value)
       
   197                     .mapToObj(AnnotationInvocationHandler::toSourceString);
       
   198             } else if (type == short[].class)
       
   199                 stringStream = convert((short[]) value);
       
   200             else if (type == boolean[].class)
       
   201                 stringStream = convert((boolean[]) value);
       
   202             else if (type == Class[].class)
       
   203                 stringStream =
       
   204                     Arrays.stream((Class<?>[]) value).
       
   205                     map(AnnotationInvocationHandler::toSourceString);
       
   206             else if (type == String[].class)
       
   207                 stringStream =
       
   208                     Arrays.stream((String[])value).
       
   209                     map(AnnotationInvocationHandler::toSourceString);
       
   210             else
       
   211                 stringStream = Arrays.stream((Object[])value).map(Objects::toString);
       
   212 
       
   213             return stringStreamToString(stringStream);
       
   214         }
       
   215     }
       
   216 
       
   217     /**
       
   218      * Translates a Class value to a form suitable for use in the
       
   219      * string representation of an annotation.
       
   220      */
       
   221     private static String toSourceString(Class<?> clazz) {
       
   222         Class<?> finalComponent = clazz;
       
   223         StringBuilder arrayBackets = new StringBuilder();
       
   224 
       
   225         while(finalComponent.isArray()) {
       
   226             finalComponent = finalComponent.getComponentType();
       
   227             arrayBackets.append("[]");
       
   228         }
       
   229 
       
   230         return finalComponent.getName() + arrayBackets.toString() + ".class" ;
       
   231     }
       
   232 
       
   233     private static String toSourceString(float f) {
       
   234         if (Float.isFinite(f))
       
   235             return Float.toString(f) + "f" ;
       
   236         else {
       
   237             if (Float.isInfinite(f)) {
       
   238                 return (f < 0.0f) ? "-1.0f/0.0f": "1.0f/0.0f";
       
   239             } else
       
   240                 return "0.0f/0.0f";
       
   241         }
       
   242     }
       
   243 
       
   244     private static String toSourceString(double d) {
       
   245         if (Double.isFinite(d))
       
   246             return Double.toString(d);
       
   247         else {
       
   248             if (Double.isInfinite(d)) {
       
   249                 return (d < 0.0f) ? "-1.0/0.0": "1.0/0.0";
       
   250             } else
       
   251                 return "0.0/0.0";
       
   252         }
       
   253     }
       
   254 
       
   255     private static String toSourceString(char c) {
       
   256         StringBuilder sb = new StringBuilder(4);
       
   257         sb.append('\'');
       
   258         if (c == '\'')
       
   259             sb.append("\\'");
       
   260         else
       
   261             sb.append(c);
       
   262         return sb.append('\'')
       
   263                 .toString();
       
   264     }
       
   265 
       
   266     private static String toSourceString(long ell) {
       
   267         String str = String.valueOf(ell);
       
   268         return (ell < Integer.MIN_VALUE || ell > Integer.MAX_VALUE)
       
   269                 ? (str + 'L') : str;
       
   270     }
       
   271 
       
   272     /**
       
   273      * Return a string suitable for use in the string representation
       
   274      * of an annotation.
       
   275      */
       
   276     private static String toSourceString(String s) {
       
   277         StringBuilder sb = new StringBuilder();
       
   278         sb.append('"');
       
   279         // Escape embedded quote characters, if present, but don't do
       
   280         // anything more heroic.
       
   281         sb.append(s.replace("\"", "\\\""));
       
   282         sb.append('"');
       
   283         return sb.toString();
       
   284     }
       
   285 
       
   286     private static Stream<String> convert(byte[] values) {
       
   287         List<String> list = new ArrayList<>(values.length);
       
   288         for (byte b : values)
       
   289             list.add(Byte.toString(b));
       
   290         return list.stream();
       
   291     }
       
   292 
       
   293     private static Stream<String> convert(char[] values) {
       
   294         List<String> list = new ArrayList<>(values.length);
       
   295         for (char c : values)
       
   296             list.add(toSourceString(c));
       
   297         return list.stream();
       
   298     }
       
   299 
       
   300     private static Stream<String> convert(float[] values) {
       
   301         List<String> list = new ArrayList<>(values.length);
       
   302         for (float f : values) {
       
   303             list.add(toSourceString(f));
       
   304         }
       
   305         return list.stream();
       
   306     }
       
   307 
       
   308     private static Stream<String> convert(short[] values) {
       
   309         List<String> list = new ArrayList<>(values.length);
       
   310         for (short s : values)
       
   311             list.add(Short.toString(s));
       
   312         return list.stream();
       
   313     }
       
   314 
       
   315     private static Stream<String> convert(boolean[] values) {
       
   316         List<String> list = new ArrayList<>(values.length);
       
   317         for (boolean b : values)
       
   318             list.add(Boolean.toString(b));
       
   319         return list.stream();
       
   320     }
       
   321 
       
   322     private static String stringStreamToString(Stream<String> stream) {
       
   323         return stream.collect(Collectors.joining(", ", "{", "}"));
       
   324     }
       
   325 
       
   326     /**
       
   327      * Implementation of dynamicProxy.equals(Object o)
       
   328      */
       
   329     private Boolean equalsImpl(Object proxy, Object o) {
       
   330         if (o == proxy)
       
   331             return true;
       
   332 
       
   333         if (!type.isInstance(o))
       
   334             return false;
       
   335         for (Method memberMethod : getMemberMethods()) {
       
   336             String member = memberMethod.getName();
       
   337             Object ourValue = memberValues.get(member);
       
   338             Object hisValue = null;
       
   339             AnnotationInvocationHandler hisHandler = asOneOfUs(o);
       
   340             if (hisHandler != null) {
       
   341                 hisValue = hisHandler.memberValues.get(member);
       
   342             } else {
       
   343                 try {
       
   344                     hisValue = memberMethod.invoke(o);
       
   345                 } catch (InvocationTargetException e) {
       
   346                     return false;
       
   347                 } catch (IllegalAccessException e) {
       
   348                     throw new AssertionError(e);
       
   349                 }
       
   350             }
       
   351             if (!memberValueEquals(ourValue, hisValue))
       
   352                 return false;
       
   353         }
       
   354         return true;
       
   355     }
       
   356 
       
   357     /**
       
   358      * Returns an object's invocation handler if that object is a dynamic
       
   359      * proxy with a handler of type AnnotationInvocationHandler.
       
   360      * Returns null otherwise.
       
   361      */
       
   362     private AnnotationInvocationHandler asOneOfUs(Object o) {
       
   363         if (Proxy.isProxyClass(o.getClass())) {
       
   364             InvocationHandler handler = Proxy.getInvocationHandler(o);
       
   365             if (handler instanceof AnnotationInvocationHandler)
       
   366                 return (AnnotationInvocationHandler) handler;
       
   367         }
       
   368         return null;
       
   369     }
       
   370 
       
   371     /**
       
   372      * Returns true iff the two member values in "dynamic proxy return form"
       
   373      * are equal using the appropriate equality function depending on the
       
   374      * member type.  The two values will be of the same type unless one of
       
   375      * the containing annotations is ill-formed.  If one of the containing
       
   376      * annotations is ill-formed, this method will return false unless the
       
   377      * two members are identical object references.
       
   378      */
       
   379     private static boolean memberValueEquals(Object v1, Object v2) {
       
   380         Class<?> type = v1.getClass();
       
   381 
       
   382         // Check for primitive, string, class, enum const, annotation,
       
   383         // or ExceptionProxy
       
   384         if (!type.isArray())
       
   385             return v1.equals(v2);
       
   386 
       
   387         // Check for array of string, class, enum const, annotation,
       
   388         // or ExceptionProxy
       
   389         if (v1 instanceof Object[] && v2 instanceof Object[])
       
   390             return Arrays.equals((Object[]) v1, (Object[]) v2);
       
   391 
       
   392         // Check for ill formed annotation(s)
       
   393         if (v2.getClass() != type)
       
   394             return false;
       
   395 
       
   396         // Deal with array of primitives
       
   397         if (type == byte[].class)
       
   398             return Arrays.equals((byte[]) v1, (byte[]) v2);
       
   399         if (type == char[].class)
       
   400             return Arrays.equals((char[]) v1, (char[]) v2);
       
   401         if (type == double[].class)
       
   402             return Arrays.equals((double[]) v1, (double[]) v2);
       
   403         if (type == float[].class)
       
   404             return Arrays.equals((float[]) v1, (float[]) v2);
       
   405         if (type == int[].class)
       
   406             return Arrays.equals((int[]) v1, (int[]) v2);
       
   407         if (type == long[].class)
       
   408             return Arrays.equals((long[]) v1, (long[]) v2);
       
   409         if (type == short[].class)
       
   410             return Arrays.equals((short[]) v1, (short[]) v2);
       
   411         assert type == boolean[].class;
       
   412         return Arrays.equals((boolean[]) v1, (boolean[]) v2);
       
   413     }
       
   414 
       
   415     /**
       
   416      * Returns the member methods for our annotation type.  These are
       
   417      * obtained lazily and cached, as they're expensive to obtain
       
   418      * and we only need them if our equals method is invoked (which should
       
   419      * be rare).
       
   420      */
       
   421     private Method[] getMemberMethods() {
       
   422         Method[] value = memberMethods;
       
   423         if (value == null) {
       
   424             value = computeMemberMethods();
       
   425             memberMethods = value;
       
   426         }
       
   427         return value;
       
   428     }
       
   429 
       
   430     private Method[] computeMemberMethods() {
       
   431         return AccessController.doPrivileged(
       
   432             new PrivilegedAction<Method[]>() {
       
   433                 public Method[] run() {
       
   434                     final Method[] methods = type.getDeclaredMethods();
       
   435                     validateAnnotationMethods(methods);
       
   436                     AccessibleObject.setAccessible(methods, true);
       
   437                     return methods;
       
   438                 }});
       
   439     }
       
   440 
       
   441     private transient volatile Method[] memberMethods;
       
   442 
       
   443     /**
       
   444      * Validates that a method is structurally appropriate for an
       
   445      * annotation type. As of Java SE 8, annotation types cannot
       
   446      * contain static methods and the declared methods of an
       
   447      * annotation type must take zero arguments and there are
       
   448      * restrictions on the return type.
       
   449      */
       
   450     private void validateAnnotationMethods(Method[] memberMethods) {
       
   451         /*
       
   452          * Specification citations below are from JLS
       
   453          * 9.6.1. Annotation Type Elements
       
   454          */
       
   455         boolean valid = true;
       
   456         for(Method method : memberMethods) {
       
   457             /*
       
   458              * "By virtue of the AnnotationTypeElementDeclaration
       
   459              * production, a method declaration in an annotation type
       
   460              * declaration cannot have formal parameters, type
       
   461              * parameters, or a throws clause.
       
   462              *
       
   463              * "By virtue of the AnnotationTypeElementModifier
       
   464              * production, a method declaration in an annotation type
       
   465              * declaration cannot be default or static."
       
   466              */
       
   467             if (method.getModifiers() != (Modifier.PUBLIC | Modifier.ABSTRACT) ||
       
   468                 method.isDefault() ||
       
   469                 method.getParameterCount() != 0 ||
       
   470                 method.getExceptionTypes().length != 0) {
       
   471                 valid = false;
       
   472                 break;
       
   473             }
       
   474 
       
   475             /*
       
   476              * "It is a compile-time error if the return type of a
       
   477              * method declared in an annotation type is not one of the
       
   478              * following: a primitive type, String, Class, any
       
   479              * parameterized invocation of Class, an enum type
       
   480              * (section 8.9), an annotation type, or an array type
       
   481              * (chapter 10) whose element type is one of the preceding
       
   482              * types."
       
   483              */
       
   484             Class<?> returnType = method.getReturnType();
       
   485             if (returnType.isArray()) {
       
   486                 returnType = returnType.getComponentType();
       
   487                 if (returnType.isArray()) { // Only single dimensional arrays
       
   488                     valid = false;
       
   489                     break;
       
   490                 }
       
   491             }
       
   492 
       
   493             if (!((returnType.isPrimitive() && returnType != void.class) ||
       
   494                   returnType == java.lang.String.class ||
       
   495                   returnType == java.lang.Class.class ||
       
   496                   returnType.isEnum() ||
       
   497                   returnType.isAnnotation())) {
       
   498                 valid = false;
       
   499                 break;
       
   500             }
       
   501 
       
   502             /*
       
   503              * "It is a compile-time error if any method declared in an
       
   504              * annotation type has a signature that is
       
   505              * override-equivalent to that of any public or protected
       
   506              * method declared in class Object or in the interface
       
   507              * java.lang.annotation.Annotation."
       
   508              *
       
   509              * The methods in Object or Annotation meeting the other
       
   510              * criteria (no arguments, contrained return type, etc.)
       
   511              * above are:
       
   512              *
       
   513              * String toString()
       
   514              * int hashCode()
       
   515              * Class<? extends Annotation> annotationType()
       
   516              */
       
   517             String methodName = method.getName();
       
   518             if ((methodName.equals("toString") && returnType == java.lang.String.class) ||
       
   519                 (methodName.equals("hashCode") && returnType == int.class) ||
       
   520                 (methodName.equals("annotationType") && returnType == java.lang.Class.class)) {
       
   521                 valid = false;
       
   522                 break;
       
   523             }
       
   524         }
       
   525         if (valid)
       
   526             return;
       
   527         else
       
   528             throw new AnnotationFormatError("Malformed method on an annotation type");
       
   529     }
       
   530 
       
   531     /**
       
   532      * Implementation of dynamicProxy.hashCode()
       
   533      */
       
   534     private int hashCodeImpl() {
       
   535         int result = 0;
       
   536         for (Map.Entry<String, Object> e : memberValues.entrySet()) {
       
   537             result += (127 * e.getKey().hashCode()) ^
       
   538                 memberValueHashCode(e.getValue());
       
   539         }
       
   540         return result;
       
   541     }
       
   542 
       
   543     /**
       
   544      * Computes hashCode of a member value (in "dynamic proxy return form")
       
   545      */
       
   546     private static int memberValueHashCode(Object value) {
       
   547         Class<?> type = value.getClass();
       
   548         if (!type.isArray())    // primitive, string, class, enum const,
       
   549                                 // or annotation
       
   550             return value.hashCode();
       
   551 
       
   552         if (type == byte[].class)
       
   553             return Arrays.hashCode((byte[]) value);
       
   554         if (type == char[].class)
       
   555             return Arrays.hashCode((char[]) value);
       
   556         if (type == double[].class)
       
   557             return Arrays.hashCode((double[]) value);
       
   558         if (type == float[].class)
       
   559             return Arrays.hashCode((float[]) value);
       
   560         if (type == int[].class)
       
   561             return Arrays.hashCode((int[]) value);
       
   562         if (type == long[].class)
       
   563             return Arrays.hashCode((long[]) value);
       
   564         if (type == short[].class)
       
   565             return Arrays.hashCode((short[]) value);
       
   566         if (type == boolean[].class)
       
   567             return Arrays.hashCode((boolean[]) value);
       
   568         return Arrays.hashCode((Object[]) value);
       
   569     }
       
   570 
       
   571     private void readObject(java.io.ObjectInputStream s)
       
   572         throws java.io.IOException, ClassNotFoundException {
       
   573         ObjectInputStream.GetField fields = s.readFields();
       
   574 
       
   575         @SuppressWarnings("unchecked")
       
   576         Class<? extends Annotation> t = (Class<? extends Annotation>)fields.get("type", null);
       
   577         @SuppressWarnings("unchecked")
       
   578         Map<String, Object> streamVals = (Map<String, Object>)fields.get("memberValues", null);
       
   579 
       
   580         // Check to make sure that types have not evolved incompatibly
       
   581 
       
   582         AnnotationType annotationType = null;
       
   583         try {
       
   584             annotationType = AnnotationType.getInstance(t);
       
   585         } catch(IllegalArgumentException e) {
       
   586             // Class is no longer an annotation type; time to punch out
       
   587             throw new java.io.InvalidObjectException("Non-annotation type in annotation serial stream");
       
   588         }
       
   589 
       
   590         Map<String, Class<?>> memberTypes = annotationType.memberTypes();
       
   591         // consistent with runtime Map type
       
   592         Map<String, Object> mv = new LinkedHashMap<>();
       
   593 
       
   594         // If there are annotation members without values, that
       
   595         // situation is handled by the invoke method.
       
   596         for (Map.Entry<String, Object> memberValue : streamVals.entrySet()) {
       
   597             String name = memberValue.getKey();
       
   598             Object value = null;
       
   599             Class<?> memberType = memberTypes.get(name);
       
   600             if (memberType != null) {  // i.e. member still exists
       
   601                 value = memberValue.getValue();
       
   602                 if (!(memberType.isInstance(value) ||
       
   603                       value instanceof ExceptionProxy)) {
       
   604                     value = new AnnotationTypeMismatchExceptionProxy(
       
   605                             value.getClass() + "[" + value + "]").setMember(
       
   606                                 annotationType.members().get(name));
       
   607                 }
       
   608             }
       
   609             mv.put(name, value);
       
   610         }
       
   611 
       
   612         UnsafeAccessor.setType(this, t);
       
   613         UnsafeAccessor.setMemberValues(this, mv);
       
   614     }
       
   615 
       
   616     private static class UnsafeAccessor {
       
   617         private static final jdk.internal.misc.Unsafe unsafe
       
   618                 = jdk.internal.misc.Unsafe.getUnsafe();
       
   619         private static final long typeOffset = unsafe.objectFieldOffset
       
   620                 (AnnotationInvocationHandler.class, "type");
       
   621         private static final long memberValuesOffset = unsafe.objectFieldOffset
       
   622                 (AnnotationInvocationHandler.class, "memberValues");
       
   623 
       
   624         static void setType(AnnotationInvocationHandler o,
       
   625                             Class<? extends Annotation> type) {
       
   626             unsafe.putObject(o, typeOffset, type);
       
   627         }
       
   628 
       
   629         static void setMemberValues(AnnotationInvocationHandler o,
       
   630                                     Map<String, Object> memberValues) {
       
   631             unsafe.putObject(o, memberValuesOffset, memberValues);
       
   632         }
       
   633     }
       
   634 }