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

Print this page

        

@@ -67,11 +67,39 @@
                 Class<?> container) {
         if (rawAnnotations == null)
             return Collections.emptyMap();
 
         try {
-            return parseAnnotations2(rawAnnotations, constPool, container);
+            return parseAnnotations2(rawAnnotations, constPool, container, null);
+        } catch(BufferUnderflowException e) {
+            throw new AnnotationFormatError("Unexpected end of annotations.");
+        } catch(IllegalArgumentException e) {
+            // Type mismatch in constant pool
+            throw new AnnotationFormatError(e);
+        }
+    }
+
+    /**
+     * An overload of {@link #parseAnnotations(byte[], sun.reflect.ConstantPool, Class)}
+     * with an additional parameter {@code selectAnnotationClasses} which selects the
+     * annotation types to parse (other than selected are quickly skipped).<p>
+     * This method is only used to parse select meta annotations in the construction
+     * phase of {@link AnnotationType} instances to prevent infinite recursion.
+     *
+     * @param selectAnnotationClasses an array of annotation types to select when parsing
+     */
+    @SafeVarargs
+    public static Map<Class<? extends Annotation>, Annotation> parseAnnotations(
+        byte[] rawAnnotations,
+        ConstantPool constPool,
+        Class<?> container,
+        Class<? extends Annotation> ... selectAnnotationClasses) {
+        if (rawAnnotations == null)
+            return Collections.emptyMap();
+
+        try {
+            return parseAnnotations2(rawAnnotations, constPool, container, selectAnnotationClasses);
         } catch(BufferUnderflowException e) {
             throw new AnnotationFormatError("Unexpected end of annotations.");
         } catch(IllegalArgumentException e) {
             // Type mismatch in constant pool
             throw new AnnotationFormatError(e);

@@ -79,26 +107,27 @@
     }
 
     private static Map<Class<? extends Annotation>, Annotation> parseAnnotations2(
                 byte[] rawAnnotations,
                 ConstantPool constPool,
-                Class<?> container) {
+                Class<?> container,
+                Class<? extends Annotation>[] selectAnnotationClasses) {
         Map<Class<? extends Annotation>, Annotation> result =
             new LinkedHashMap<Class<? extends Annotation>, Annotation>();
         ByteBuffer buf = ByteBuffer.wrap(rawAnnotations);
         int numAnnotations = buf.getShort() & 0xFFFF;
         for (int i = 0; i < numAnnotations; i++) {
-            Annotation a = parseAnnotation(buf, constPool, container, false);
+            Annotation a = parseAnnotation(buf, constPool, container, false, selectAnnotationClasses);
             if (a != null) {
                 Class<? extends Annotation> klass = a.annotationType();
-                AnnotationType type = AnnotationType.getInstance(klass);
-                if (type.retention() == RetentionPolicy.RUNTIME)
-                    if (result.put(klass, a) != null)
+                if (AnnotationType.getInstance(klass).retention() == RetentionPolicy.RUNTIME &&
+                    result.put(klass, a) != null) {
                         throw new AnnotationFormatError(
                             "Duplicate annotation for class: "+klass+": " + a);
             }
         }
+        }
         return result;
     }
 
     /**
      * Parses the parameter annotations described by the specified byte array.

@@ -149,11 +178,11 @@
         for (int i = 0; i < numParameters; i++) {
             int numAnnotations = buf.getShort() & 0xFFFF;
             List<Annotation> annotations =
                 new ArrayList<Annotation>(numAnnotations);
             for (int j = 0; j < numAnnotations; j++) {
-                Annotation a = parseAnnotation(buf, constPool, container, false);
+                Annotation a = parseAnnotation(buf, constPool, container, false, null);
                 if (a != null) {
                     AnnotationType type = AnnotationType.getInstance(
                                               a.annotationType());
                     if (type.retention() == RetentionPolicy.RUNTIME)
                         annotations.add(a);

@@ -191,11 +220,12 @@
      */
     @SuppressWarnings("unchecked")
     static Annotation parseAnnotation(ByteBuffer buf,
                                               ConstantPool constPool,
                                               Class<?> container,
-                                              boolean exceptionOnMissingAnnotationClass) {
+                                              boolean exceptionOnMissingAnnotationClass,
+                                              Class<? extends Annotation>[] selectAnnotationClasses) {
         int typeIndex = buf.getShort() & 0xFFFF;
         Class<? extends Annotation> annotationClass = null;
         String sig = "[unknown]";
         try {
             try {

@@ -217,10 +247,14 @@
             if (exceptionOnMissingAnnotationClass)
                 throw e;
             skipAnnotation(buf, false);
             return null;
         }
+        if (selectAnnotationClasses != null && !contains(selectAnnotationClasses, annotationClass)) {
+            skipAnnotation(buf, false);
+            return null;
+        }
         AnnotationType type = null;
         try {
             type = AnnotationType.getInstance(annotationClass);
         } catch (IllegalArgumentException e) {
             skipAnnotation(buf, false);

@@ -305,11 +339,11 @@
               return parseEnumValue((Class<? extends Enum<?>>)memberType, buf, constPool, container);
           case 'c':
               result = parseClassValue(buf, constPool, container);
               break;
           case '@':
-              result = parseAnnotation(buf, constPool, container, true);
+              result = parseAnnotation(buf, constPool, container, true, null);
               break;
           case '[':
               return parseArray(memberType, buf, constPool, container);
           default:
               result = parseConst(tag, buf, constPool);

@@ -718,11 +752,11 @@
         int tag = 0;
 
         for (int i = 0; i < length; i++) {
             tag = buf.get();
             if (tag == '@') {
-                result[i] = parseAnnotation(buf, constPool, container, true);
+                result[i] = parseAnnotation(buf, constPool, container, true, null);
             } else {
                 skipMemberValue(tag, buf);
                 typeMismatch = true;
             }
         }

@@ -798,10 +832,18 @@
         int length = buf.getShort() & 0xFFFF;
         for (int i = 0; i < length; i++)
             skipMemberValue(buf);
     }
 
+    // utility
+    private static boolean contains(Object[] array, Object element) {
+        for (Object e : array)
+            if (e == element)
+                return true;
+        return false;
+    }
+
     /*
      * This method converts the annotation map returned by the parseAnnotations()
      * method to an array.  It is called by Field.getDeclaredAnnotations(),
      * Method.getDeclaredAnnotations(), and Constructor.getDeclaredAnnotations().
      * This avoids the reflection classes to load the Annotation class until