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

Print this page


   1 /*
   2  * Copyright (c) 2003, 2005, 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


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




























  79     private static Map<Class<? extends Annotation>, Annotation> parseAnnotations2(
  80                 byte[] rawAnnotations,
  81                 ConstantPool constPool,
  82                 Class<?> container) {

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

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


 174      * annotation {
 175      *    u2    type_index;
 176      *       u2    num_member_value_pairs;
 177      *       {    u2    member_name_index;
 178      *             member_value value;
 179      *       }    member_value_pairs[num_member_value_pairs];
 180      *    }
 181      * }
 182      *
 183      * Returns the annotation, or null if the annotation's type cannot
 184      * be found by the VM, or is not a valid annotation type.
 185      *
 186      * @param exceptionOnMissingAnnotationClass if true, throw
 187      * TypeNotPresentException if a referenced annotation type is not
 188      * available at runtime
 189      */
 190     private static Annotation parseAnnotation(ByteBuffer buf,
 191                                               ConstantPool constPool,
 192                                               Class<?> container,
 193                                               boolean exceptionOnMissingAnnotationClass) {









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




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


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











 794     /*
 795      * This method converts the annotation map returned by the parseAnnotations()
 796      * method to an array.  It is called by Field.getDeclaredAnnotations(),
 797      * Method.getDeclaredAnnotations(), and Constructor.getDeclaredAnnotations().
 798      * This avoids the reflection classes to load the Annotation class until
 799      * it is needed.
 800      */
 801     private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
 802     public static Annotation[] toArray(Map<Class<? extends Annotation>, Annotation> annotations) {
 803         return annotations.values().toArray(EMPTY_ANNOTATION_ARRAY);
 804     }
 805 }
   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


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

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


 203      * annotation {
 204      *    u2    type_index;
 205      *       u2    num_member_value_pairs;
 206      *       {    u2    member_name_index;
 207      *             member_value value;
 208      *       }    member_value_pairs[num_member_value_pairs];
 209      *    }
 210      * }
 211      *
 212      * Returns the annotation, or null if the annotation's type cannot
 213      * be found by the VM, or is not a valid annotation type.
 214      *
 215      * @param exceptionOnMissingAnnotationClass if true, throw
 216      * TypeNotPresentException if a referenced annotation type is not
 217      * available at runtime
 218      */
 219     private static Annotation parseAnnotation(ByteBuffer buf,
 220                                               ConstantPool constPool,
 221                                               Class<?> container,
 222                                               boolean exceptionOnMissingAnnotationClass) {
 223        return parseAnnotation2(buf, constPool, container, exceptionOnMissingAnnotationClass, null);
 224     }
 225 
 226     @SuppressWarnings("unchecked")
 227     private static Annotation parseAnnotation2(ByteBuffer buf,
 228                                               ConstantPool constPool,
 229                                               Class<?> container,
 230                                               boolean exceptionOnMissingAnnotationClass,
 231                                               Class<? extends Annotation>[] selectAnnotationClasses) {
 232         int typeIndex = buf.getShort() & 0xFFFF;
 233         Class<? extends Annotation> annotationClass = null;
 234         String sig = "[unknown]";
 235         try {
 236             try {
 237                 sig = constPool.getUTF8At(typeIndex);
 238                 annotationClass = (Class<? extends Annotation>)parseSig(sig, container);
 239             } catch (IllegalArgumentException ex) {
 240                 // support obsolete early jsr175 format class files
 241                 annotationClass = constPool.getClassAt(typeIndex);
 242             }
 243         } catch (NoClassDefFoundError e) {
 244             if (exceptionOnMissingAnnotationClass)
 245                 // note: at this point sig is "[unknown]" or VM-style
 246                 // name instead of a binary name
 247                 throw new TypeNotPresentException(sig, e);
 248             skipAnnotation(buf, false);
 249             return null;
 250         }
 251         catch (TypeNotPresentException e) {
 252             if (exceptionOnMissingAnnotationClass)
 253                 throw e;
 254             skipAnnotation(buf, false);
 255             return null;
 256         }
 257         if (selectAnnotationClasses != null && !contains(selectAnnotationClasses, annotationClass)) {
 258             skipAnnotation(buf, false);
 259             return null;
 260         }
 261         AnnotationType type = null;
 262         try {
 263             type = AnnotationType.getInstance(annotationClass);
 264         } catch (IllegalArgumentException e) {
 265             skipAnnotation(buf, false);
 266             return null;
 267         }
 268 
 269         Map<String, Class<?>> memberTypes = type.memberTypes();
 270         Map<String, Object> memberValues =
 271             new LinkedHashMap<String, Object>(type.memberDefaults());
 272 
 273         int numMembers = buf.getShort() & 0xFFFF;
 274         for (int i = 0; i < numMembers; i++) {
 275             int memberNameIndex = buf.getShort() & 0xFFFF;
 276             String memberName = constPool.getUTF8At(memberNameIndex);
 277             Class<?> memberType = memberTypes.get(memberName);
 278 
 279             if (memberType == null) {
 280                 // Member is no longer present in annotation type; ignore it


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