src/share/classes/sun/reflect/annotation/AnnotationParser.java

Print this page




  52     /**
  53      * Parses the annotations described by the specified byte array.
  54      * resolving constant references in the specified constant pool.
  55      * The array must contain an array of annotations as described
  56      * in the RuntimeVisibleAnnotations_attribute:
  57      *
  58      *   u2 num_annotations;
  59      *   annotation annotations[num_annotations];
  60      *
  61      * @throws AnnotationFormatError if an annotation is found to be
  62      *         malformed.
  63      */
  64     public static Map<Class<? extends Annotation>, Annotation> parseAnnotations(
  65                 byte[] rawAnnotations,
  66                 ConstantPool constPool,
  67                 Class<?> container) {
  68         if (rawAnnotations == null)
  69             return Collections.emptyMap();
  70 
  71         try {
  72             return parseAnnotations2(rawAnnotations, constPool, container);




























  73         } catch(BufferUnderflowException e) {
  74             throw new AnnotationFormatError("Unexpected end of annotations.");
  75         } catch(IllegalArgumentException e) {
  76             // Type mismatch in constant pool
  77             throw new AnnotationFormatError(e);
  78         }
  79     }
  80 
  81     private static Map<Class<? extends Annotation>, Annotation> parseAnnotations2(
  82                 byte[] rawAnnotations,
  83                 ConstantPool constPool,
  84                 Class<?> container) {

  85         Map<Class<? extends Annotation>, Annotation> result =
  86             new LinkedHashMap<Class<? extends Annotation>, Annotation>();
  87         ByteBuffer buf = ByteBuffer.wrap(rawAnnotations);
  88         int numAnnotations = buf.getShort() & 0xFFFF;
  89         for (int i = 0; i < numAnnotations; i++) {
  90             Annotation a = parseAnnotation(buf, constPool, container, false);
  91             if (a != null) {
  92                 Class<? extends Annotation> klass = a.annotationType();
  93                 AnnotationType type = AnnotationType.getInstance(klass);
  94                 if (type.retention() == RetentionPolicy.RUNTIME)
  95                     if (result.put(klass, a) != null)
  96                         throw new AnnotationFormatError(
  97                             "Duplicate annotation for class: "+klass+": " + a);
  98             }
  99         }

 100         return result;
 101     }
 102 
 103     /**
 104      * Parses the parameter annotations described by the specified byte array.
 105      * resolving constant references in the specified constant pool.
 106      * The array must contain an array of annotations as described
 107      * in the RuntimeVisibleParameterAnnotations_attribute:
 108      *
 109      *    u1 num_parameters;
 110      *    {
 111      *        u2 num_annotations;
 112      *        annotation annotations[num_annotations];
 113      *    } parameter_annotations[num_parameters];
 114      *
 115      * Unlike parseAnnotations, rawAnnotations must not be null!
 116      * A null value must be handled by the caller.  This is so because
 117      * we cannot determine the number of parameters if rawAnnotations
 118      * is null.  Also, the caller should check that the number
 119      * of parameters indicated by the return value of this method


 172      * byte buffer, resolving constant references in the specified constant
 173      * pool.  The cursor of the byte buffer must point to an "annotation
 174      * structure" as described in the RuntimeVisibleAnnotations_attribute:
 175      *
 176      * annotation {
 177      *    u2    type_index;
 178      *       u2    num_member_value_pairs;
 179      *       {    u2    member_name_index;
 180      *             member_value value;
 181      *       }    member_value_pairs[num_member_value_pairs];
 182      *    }
 183      * }
 184      *
 185      * Returns the annotation, or null if the annotation's type cannot
 186      * be found by the VM, or is not a valid annotation type.
 187      *
 188      * @param exceptionOnMissingAnnotationClass if true, throw
 189      * TypeNotPresentException if a referenced annotation type is not
 190      * available at runtime
 191      */
 192     @SuppressWarnings("unchecked")
 193     static Annotation parseAnnotation(ByteBuffer buf,
 194                                               ConstantPool constPool,
 195                                               Class<?> container,
 196                                               boolean exceptionOnMissingAnnotationClass) {









 197         int typeIndex = buf.getShort() & 0xFFFF;
 198         Class<? extends Annotation> annotationClass = null;
 199         String sig = "[unknown]";
 200         try {
 201             try {
 202                 sig = constPool.getUTF8At(typeIndex);
 203                 annotationClass = (Class<? extends Annotation>)parseSig(sig, container);
 204             } catch (IllegalArgumentException ex) {
 205                 // support obsolete early jsr175 format class files
 206                 annotationClass = (Class<? extends Annotation>)constPool.getClassAt(typeIndex);
 207             }
 208         } catch (NoClassDefFoundError e) {
 209             if (exceptionOnMissingAnnotationClass)
 210                 // note: at this point sig is "[unknown]" or VM-style
 211                 // name instead of a binary name
 212                 throw new TypeNotPresentException(sig, e);
 213             skipAnnotation(buf, false);
 214             return null;
 215         }
 216         catch (TypeNotPresentException e) {
 217             if (exceptionOnMissingAnnotationClass)
 218                 throw e;
 219             skipAnnotation(buf, false);
 220             return null;
 221         }




 222         AnnotationType type = null;
 223         try {
 224             type = AnnotationType.getInstance(annotationClass);
 225         } catch (IllegalArgumentException e) {
 226             skipAnnotation(buf, false);
 227             return null;
 228         }
 229 
 230         Map<String, Class<?>> memberTypes = type.memberTypes();
 231         Map<String, Object> memberValues =
 232             new LinkedHashMap<String, Object>(type.memberDefaults());
 233 
 234         int numMembers = buf.getShort() & 0xFFFF;
 235         for (int i = 0; i < numMembers; i++) {
 236             int memberNameIndex = buf.getShort() & 0xFFFF;
 237             String memberName = constPool.getUTF8At(memberNameIndex);
 238             Class<?> memberType = memberTypes.get(memberName);
 239 
 240             if (memberType == null) {
 241                 // Member is no longer present in annotation type; ignore it


 781             skipAnnotation(buf, true);
 782             break;
 783           case '[':
 784             skipArray(buf);
 785             break;
 786           default:
 787             // Class, primitive, or String
 788             buf.getShort();
 789         }
 790     }
 791 
 792     /**
 793      * Skips the array value at the current position in the specified byte
 794      * buffer.  The cursor of the byte buffer must point to an array value
 795      * struct.
 796      */
 797     private static void skipArray(ByteBuffer buf) {
 798         int length = buf.getShort() & 0xFFFF;
 799         for (int i = 0; i < length; i++)
 800             skipMemberValue(buf);











 801     }
 802 
 803     /*
 804      * This method converts the annotation map returned by the parseAnnotations()
 805      * method to an array.  It is called by Field.getDeclaredAnnotations(),
 806      * Method.getDeclaredAnnotations(), and Constructor.getDeclaredAnnotations().
 807      * This avoids the reflection classes to load the Annotation class until
 808      * it is needed.
 809      */
 810     private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
 811     public static Annotation[] toArray(Map<Class<? extends Annotation>, Annotation> annotations) {
 812         return annotations.values().toArray(EMPTY_ANNOTATION_ARRAY);
 813     }
 814 
 815     static Annotation[] getEmptyAnnotationArray() { return EMPTY_ANNOTATION_ARRAY; }
 816 }


  52     /**
  53      * Parses the annotations described by the specified byte array.
  54      * resolving constant references in the specified constant pool.
  55      * The array must contain an array of annotations as described
  56      * in the RuntimeVisibleAnnotations_attribute:
  57      *
  58      *   u2 num_annotations;
  59      *   annotation annotations[num_annotations];
  60      *
  61      * @throws AnnotationFormatError if an annotation is found to be
  62      *         malformed.
  63      */
  64     public static Map<Class<? extends Annotation>, Annotation> parseAnnotations(
  65                 byte[] rawAnnotations,
  66                 ConstantPool constPool,
  67                 Class<?> container) {
  68         if (rawAnnotations == null)
  69             return Collections.emptyMap();
  70 
  71         try {
  72             return parseAnnotations2(rawAnnotations, constPool, container, null);
  73         } catch(BufferUnderflowException e) {
  74             throw new AnnotationFormatError("Unexpected end of annotations.");
  75         } catch(IllegalArgumentException e) {
  76             // Type mismatch in constant pool
  77             throw new AnnotationFormatError(e);
  78         }
  79     }
  80 
  81     /**
  82      * Like {@link #parseAnnotations(byte[], sun.reflect.ConstantPool, Class)}
  83      * with an additional parameter {@code selectAnnotationClasses} which selects the
  84      * annotation types to parse (other than selected are quickly skipped).<p>
  85      * This method is only used to parse select meta annotations in the construction
  86      * phase of {@link AnnotationType} instances to prevent infinite recursion.
  87      *
  88      * @param selectAnnotationClasses an array of annotation types to select when parsing
  89      */
  90     @SafeVarargs
  91     static Map<Class<? extends Annotation>, Annotation> parseSelectAnnotations(
  92                 byte[] rawAnnotations,
  93                 ConstantPool constPool,
  94                 Class<?> container,
  95                 Class<? extends Annotation> ... selectAnnotationClasses) {
  96         if (rawAnnotations == null)
  97             return Collections.emptyMap();
  98 
  99         try {
 100             return parseAnnotations2(rawAnnotations, constPool, container, selectAnnotationClasses);
 101         } catch(BufferUnderflowException e) {
 102             throw new AnnotationFormatError("Unexpected end of annotations.");
 103         } catch(IllegalArgumentException e) {
 104             // Type mismatch in constant pool
 105             throw new AnnotationFormatError(e);
 106         }
 107     }
 108 
 109     private static Map<Class<? extends Annotation>, Annotation> parseAnnotations2(
 110                 byte[] rawAnnotations,
 111                 ConstantPool constPool,
 112                 Class<?> container,
 113                 Class<? extends Annotation>[] selectAnnotationClasses) {
 114         Map<Class<? extends Annotation>, Annotation> result =
 115             new LinkedHashMap<Class<? extends Annotation>, Annotation>();
 116         ByteBuffer buf = ByteBuffer.wrap(rawAnnotations);
 117         int numAnnotations = buf.getShort() & 0xFFFF;
 118         for (int i = 0; i < numAnnotations; i++) {
 119             Annotation a = parseAnnotation2(buf, constPool, container, false, selectAnnotationClasses);
 120             if (a != null) {
 121                 Class<? extends Annotation> klass = a.annotationType();
 122                 if (AnnotationType.getInstance(klass).retention() == RetentionPolicy.RUNTIME &&
 123                     result.put(klass, a) != null) {

 124                     throw new AnnotationFormatError(
 125                         "Duplicate annotation for class: "+klass+": " + a);
 126                 }
 127             }
 128         }
 129         return result;
 130     }
 131 
 132     /**
 133      * Parses the parameter annotations described by the specified byte array.
 134      * resolving constant references in the specified constant pool.
 135      * The array must contain an array of annotations as described
 136      * in the RuntimeVisibleParameterAnnotations_attribute:
 137      *
 138      *    u1 num_parameters;
 139      *    {
 140      *        u2 num_annotations;
 141      *        annotation annotations[num_annotations];
 142      *    } parameter_annotations[num_parameters];
 143      *
 144      * Unlike parseAnnotations, rawAnnotations must not be null!
 145      * A null value must be handled by the caller.  This is so because
 146      * we cannot determine the number of parameters if rawAnnotations
 147      * is null.  Also, the caller should check that the number
 148      * of parameters indicated by the return value of this method


 201      * byte buffer, resolving constant references in the specified constant
 202      * pool.  The cursor of the byte buffer must point to an "annotation
 203      * structure" as described in the RuntimeVisibleAnnotations_attribute:
 204      *
 205      * annotation {
 206      *    u2    type_index;
 207      *       u2    num_member_value_pairs;
 208      *       {    u2    member_name_index;
 209      *             member_value value;
 210      *       }    member_value_pairs[num_member_value_pairs];
 211      *    }
 212      * }
 213      *
 214      * Returns the annotation, or null if the annotation's type cannot
 215      * be found by the VM, or is not a valid annotation type.
 216      *
 217      * @param exceptionOnMissingAnnotationClass if true, throw
 218      * TypeNotPresentException if a referenced annotation type is not
 219      * available at runtime
 220      */

 221     static Annotation parseAnnotation(ByteBuffer buf,
 222                                       ConstantPool constPool,
 223                                       Class<?> container,
 224                                       boolean exceptionOnMissingAnnotationClass) {
 225        return parseAnnotation2(buf, constPool, container, exceptionOnMissingAnnotationClass, null);
 226     }
 227 
 228     @SuppressWarnings("unchecked")
 229     private static Annotation parseAnnotation2(ByteBuffer buf,
 230                                               ConstantPool constPool,
 231                                               Class<?> container,
 232                                               boolean exceptionOnMissingAnnotationClass,
 233                                               Class<? extends Annotation>[] selectAnnotationClasses) {
 234         int typeIndex = buf.getShort() & 0xFFFF;
 235         Class<? extends Annotation> annotationClass = null;
 236         String sig = "[unknown]";
 237         try {
 238             try {
 239                 sig = constPool.getUTF8At(typeIndex);
 240                 annotationClass = (Class<? extends Annotation>)parseSig(sig, container);
 241             } catch (IllegalArgumentException ex) {
 242                 // support obsolete early jsr175 format class files
 243                 annotationClass = (Class<? extends Annotation>)constPool.getClassAt(typeIndex);
 244             }
 245         } catch (NoClassDefFoundError e) {
 246             if (exceptionOnMissingAnnotationClass)
 247                 // note: at this point sig is "[unknown]" or VM-style
 248                 // name instead of a binary name
 249                 throw new TypeNotPresentException(sig, e);
 250             skipAnnotation(buf, false);
 251             return null;
 252         }
 253         catch (TypeNotPresentException e) {
 254             if (exceptionOnMissingAnnotationClass)
 255                 throw e;
 256             skipAnnotation(buf, false);
 257             return null;
 258         }
 259         if (selectAnnotationClasses != null && !contains(selectAnnotationClasses, annotationClass)) {
 260             skipAnnotation(buf, false);
 261             return null;
 262         }
 263         AnnotationType type = null;
 264         try {
 265             type = AnnotationType.getInstance(annotationClass);
 266         } catch (IllegalArgumentException e) {
 267             skipAnnotation(buf, false);
 268             return null;
 269         }
 270 
 271         Map<String, Class<?>> memberTypes = type.memberTypes();
 272         Map<String, Object> memberValues =
 273             new LinkedHashMap<String, Object>(type.memberDefaults());
 274 
 275         int numMembers = buf.getShort() & 0xFFFF;
 276         for (int i = 0; i < numMembers; i++) {
 277             int memberNameIndex = buf.getShort() & 0xFFFF;
 278             String memberName = constPool.getUTF8At(memberNameIndex);
 279             Class<?> memberType = memberTypes.get(memberName);
 280 
 281             if (memberType == null) {
 282                 // Member is no longer present in annotation type; ignore it


 822             skipAnnotation(buf, true);
 823             break;
 824           case '[':
 825             skipArray(buf);
 826             break;
 827           default:
 828             // Class, primitive, or String
 829             buf.getShort();
 830         }
 831     }
 832 
 833     /**
 834      * Skips the array value at the current position in the specified byte
 835      * buffer.  The cursor of the byte buffer must point to an array value
 836      * struct.
 837      */
 838     private static void skipArray(ByteBuffer buf) {
 839         int length = buf.getShort() & 0xFFFF;
 840         for (int i = 0; i < length; i++)
 841             skipMemberValue(buf);
 842     }
 843 
 844     /**
 845      * Searches for given {@code element} in given {@code array} by identity.
 846      * Returns {@code true} if found {@code false} if not.
 847      */
 848     private static boolean contains(Object[] array, Object element) {
 849         for (Object e : array)
 850             if (e == element)
 851                 return true;
 852         return false;
 853     }
 854 
 855     /*
 856      * This method converts the annotation map returned by the parseAnnotations()
 857      * method to an array.  It is called by Field.getDeclaredAnnotations(),
 858      * Method.getDeclaredAnnotations(), and Constructor.getDeclaredAnnotations().
 859      * This avoids the reflection classes to load the Annotation class until
 860      * it is needed.
 861      */
 862     private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
 863     public static Annotation[] toArray(Map<Class<? extends Annotation>, Annotation> annotations) {
 864         return annotations.values().toArray(EMPTY_ANNOTATION_ARRAY);
 865     }
 866 
 867     static Annotation[] getEmptyAnnotationArray() { return EMPTY_ANNOTATION_ARRAY; }
 868 }