Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
  /*
   * Copyright 2003-2005 Sun Microsystems, Inc.  All Rights Reserved.
   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   *
   * This code is free software; you can redistribute it and/or modify it
   * under the terms of the GNU General Public License version 2 only, as
   * published by the Free Software Foundation.  Sun designates this
   * particular file as subject to the "Classpath" exception as provided
   * by Sun in the LICENSE file that accompanied this code.
  *
  * This code is distributed in the hope that it will be useful, but WITHOUT
  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  * version 2 for more details (a copy is included in the LICENSE file that
  * accompanied this code).
  *
  * You should have received a copy of the GNU General Public License version
  * 2 along with this work; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  *
  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  * CA 95054 USA or visit www.sun.com if you need additional information or
  * have any questions.
  */
 
 package sun.reflect.annotation;
 
 import java.util.*;
 
Parser for Java programming language annotations. Translates annotation byte streams emitted by compiler into annotation objects.

Author(s):
Josh Bloch
Since:
1.5
 
 public class AnnotationParser {
    
Parses the annotations described by the specified byte array. resolving constant references in the specified constant pool. The array must contain an array of annotations as described in the RuntimeVisibleAnnotations_attribute: u2 num_annotations; annotation annotations[num_annotations];

Throws:
java.lang.annotation.AnnotationFormatError if an annotation is found to be malformed.
 
     public static Map<ClassAnnotationparseAnnotations(
                 byte[] rawAnnotations,
                 ConstantPool constPool,
                 Class container) {
         if (rawAnnotations == null)
             return Collections.emptyMap();
 
         try {
             return parseAnnotations2(rawAnnotationsconstPoolcontainer);
         } catch(BufferUnderflowException e) {
             throw new AnnotationFormatError("Unexpected end of annotations.");
         } catch(IllegalArgumentException e) {
             // Type mismatch in constant pool
             throw new AnnotationFormatError(e);
         }
     }
 
     private static Map<ClassAnnotationparseAnnotations2(
                 byte[] rawAnnotations,
                 ConstantPool constPool,
                 Class container) {
         Map<ClassAnnotationresult = new LinkedHashMap<ClassAnnotation>();
         ByteBuffer buf = ByteBuffer.wrap(rawAnnotations);
         int numAnnotations = buf.getShort() & 0xFFFF;
         for (int i = 0; i < numAnnotationsi++) {
             Annotation a = parseAnnotation(bufconstPoolcontainerfalse);
             if (a != null) {
                 Class klass = a.annotationType();
                 AnnotationType type = AnnotationType.getInstance(klass);
                 if (type.retention() == .)
                     if (result.put(klassa) != null)
                         throw new AnnotationFormatError(
                             "Duplicate annotation for class: "+klass+": " + a);
             }
         }
         return result;
     }

    
Parses the parameter annotations described by the specified byte array. resolving constant references in the specified constant pool. The array must contain an array of annotations as described in the RuntimeVisibleParameterAnnotations_attribute: u1 num_parameters; { u2 num_annotations; annotation annotations[num_annotations]; } parameter_annotations[num_parameters]; Unlike parseAnnotations, rawAnnotations must not be null! A null value must be handled by the caller. This is so because we cannot determine the number of parameters if rawAnnotations is null. Also, the caller should check that the number of parameters indicated by the return value of this method matches the actual number of method parameters. A mismatch indicates that an AnnotationFormatError should be thrown.

Throws:
java.lang.annotation.AnnotationFormatError if an annotation is found to be malformed.
    public static Annotation[][] parseParameterAnnotations(
                    byte[] rawAnnotations,
                    ConstantPool constPool,
                    Class container) {
        try {
            return parseParameterAnnotations2(rawAnnotationsconstPoolcontainer);
        } catch(BufferUnderflowException e) {
            throw new AnnotationFormatError(
                "Unexpected end of parameter annotations.");
        } catch(IllegalArgumentException e) {
            // Type mismatch in constant pool
            throw new AnnotationFormatError(e);
        }
    }
    private static Annotation[][] parseParameterAnnotations2(
                    byte[] rawAnnotations,
                    ConstantPool constPool,
                    Class container) {
        ByteBuffer buf = ByteBuffer.wrap(rawAnnotations);
        int numParameters = buf.get() & 0xFF;
        Annotation[][] result = new Annotation[numParameters][];
        for (int i = 0; i < numParametersi++) {
            int numAnnotations = buf.getShort() & 0xFFFF;
            List<Annotationannotations =
                new ArrayList<Annotation>(numAnnotations);
            for (int j = 0; j < numAnnotationsj++) {
                Annotation a = parseAnnotation(bufconstPoolcontainerfalse);
                if (a != null) {
                    AnnotationType type = AnnotationType.getInstance(
                                              a.annotationType());
                    if (type.retention() == .)
                        annotations.add(a);
                }
            }
            result[i] = annotations.toArray();
        }
        return result;
    }
    private static final Annotation[] EMPTY_ANNOTATIONS_ARRAY =
                    new Annotation[0];

    
Parses the annotation at the current position in the specified byte buffer, resolving constant references in the specified constant pool. The cursor of the byte buffer must point to an "annotation structure" as described in the RuntimeVisibleAnnotations_attribute: annotation { u2 type_index; u2 num_member_value_pairs; { u2 member_name_index; member_value value; } member_value_pairs[num_member_value_pairs]; } } Returns the annotation, or null if the annotation's type cannot be found by the VM, or is not a valid annotation type.

Parameters:
exceptionOnMissingAnnotationClass if true, throw TypeNotPresentException if a referenced annotation type is not available at runtime
    private static Annotation parseAnnotation(ByteBuffer buf,
                                              ConstantPool constPool,
                                              Class container,
                                              boolean exceptionOnMissingAnnotationClass) {
        int typeIndex = buf.getShort() & 0xFFFF;
        Class annotationClass = null;
        String sig = "[unknown]";
        try {
            try {
                sig = constPool.getUTF8At(typeIndex);
                annotationClass = parseSig(sigcontainer);
            } catch (IllegalArgumentException ex) {
                // support obsolete early jsr175 format class files
                annotationClass = constPool.getClassAt(typeIndex);
            }
        } catch (NoClassDefFoundError e) {
            if (exceptionOnMissingAnnotationClass)
                // note: at this point sig is "[unknown]" or VM-style
                // name instead of a binary name
                throw new TypeNotPresentException(sige);
            skipAnnotation(buffalse);
            return null;
        }
        catch (TypeNotPresentException e) {
            if (exceptionOnMissingAnnotationClass)
                throw e;
            skipAnnotation(buffalse);
            return null;
        }
        AnnotationType type = null;
        try {
            type = AnnotationType.getInstance(annotationClass);
        } catch (IllegalArgumentException e) {
            skipAnnotation(buffalse);
            return null;
        }
        Map<StringClassmemberTypes = type.memberTypes();
        Map<StringObjectmemberValues =
            new LinkedHashMap<StringObject>(type.memberDefaults());
        int numMembers = buf.getShort() & 0xFFFF;
        for (int i = 0; i < numMembersi++) {
            int memberNameIndex = buf.getShort() & 0xFFFF;
            String memberName = constPool.getUTF8At(memberNameIndex);
            Class memberType = memberTypes.get(memberName);
            if (memberType == null) {
                // Member is no longer present in annotation type; ignore it
                skipMemberValue(buf);
            } else {
                Object value = parseMemberValue(memberTypebufconstPoolcontainer);
                if (value instanceof AnnotationTypeMismatchExceptionProxy)
                    ((AnnotationTypeMismatchExceptionProxyvalue).
                        setMember(type.members().get(memberName));
                memberValues.put(memberNamevalue);
            }
        }
        return annotationForMap(annotationClassmemberValues);
    }

    
Returns an annotation of the given type backed by the given member -> value map.
    public static Annotation annotationForMap(
        Class typeMap<StringObjectmemberValues)
    {
        return (Annotation) Proxy.newProxyInstance(
            type.getClassLoader(), new Class[] { type },
            new AnnotationInvocationHandler(typememberValues));
    }

    
Parses the annotation member value at the current position in the specified byte buffer, resolving constant references in the specified constant pool. The cursor of the byte buffer must point to a "member_value structure" as described in the RuntimeVisibleAnnotations_attribute: member_value { u1 tag; union { u2 const_value_index; { u2 type_name_index; u2 const_name_index; } enum_const_value; u2 class_info_index; annotation annotation_value; { u2 num_values; member_value values[num_values]; } array_value; } value; } The member must be of the indicated type. If it is not, this method returns an AnnotationTypeMismatchExceptionProxy.
    public static Object parseMemberValue(Class memberTypeByteBuffer buf,
                                          ConstantPool constPool,
                                          Class container) {
        Object result = null;
        int tag = buf.get();
        switch(tag) {
          case 'e':
              return parseEnumValue(memberTypebufconstPoolcontainer);
          case 'c':
              result = parseClassValue(bufconstPoolcontainer);
              break;
          case '@':
              result = parseAnnotation(bufconstPoolcontainertrue);
              break;
          case '[':
              return parseArray(memberTypebufconstPoolcontainer);
          default:
              result = parseConst(tagbufconstPool);
        }
        if (!(result instanceof ExceptionProxy) &&
            !memberType.isInstance(result))
            result = new AnnotationTypeMismatchExceptionProxy(
                result.getClass() + "[" + result + "]");
        return result;
    }

    
Parses the primitive or String annotation member value indicated by the specified tag byte at the current position in the specified byte buffer, resolving constant reference in the specified constant pool. The cursor of the byte buffer must point to an annotation member value of the type indicated by the specified tag, as described in the RuntimeVisibleAnnotations_attribute: u2 const_value_index;
    private static Object parseConst(int tag,
                                     ByteBuffer bufConstantPool constPool) {
        int constIndex = buf.getShort() & 0xFFFF;
        switch(tag) {
          case 'B':
            return Byte.valueOf((byteconstPool.getIntAt(constIndex));
          case 'C':
            return Character.valueOf((charconstPool.getIntAt(constIndex));
          case 'D':
            return Double.valueOf(constPool.getDoubleAt(constIndex));
          case 'F':
            return Float.valueOf(constPool.getFloatAt(constIndex));
          case 'I':
            return Integer.valueOf(constPool.getIntAt(constIndex));
          case 'J':
            return Long.valueOf(constPool.getLongAt(constIndex));
          case 'S':
            return Short.valueOf((shortconstPool.getIntAt(constIndex));
          case 'Z':
            return Boolean.valueOf(constPool.getIntAt(constIndex) != 0);
          case 's':
            return constPool.getUTF8At(constIndex);
          default:
            throw new AnnotationFormatError(
                "Invalid member-value tag in annotation: " + tag);
        }
    }

    
Parses the Class member value at the current position in the specified byte buffer, resolving constant references in the specified constant pool. The cursor of the byte buffer must point to a "class info index" as described in the RuntimeVisibleAnnotations_attribute: u2 class_info_index;
    private static Object parseClassValue(ByteBuffer buf,
                                          ConstantPool constPool,
                                          Class container) {
        int classIndex = buf.getShort() & 0xFFFF;
        try {
            try {
                String sig = constPool.getUTF8At(classIndex);
                return parseSig(sigcontainer);
            } catch (IllegalArgumentException ex) {
                // support obsolete early jsr175 format class files
                return constPool.getClassAt(classIndex);
            }
        } catch (NoClassDefFoundError e) {
            return new TypeNotPresentExceptionProxy("[unknown]"e);
        }
        catch (TypeNotPresentException e) {
            return new TypeNotPresentExceptionProxy(e.typeName(), e.getCause());
        }
    }
    private static Class<?> parseSig(String sigClass container) {
        if (sig.equals("V")) return void.class;
        SignatureParser parser = SignatureParser.make();
        TypeSignature typeSig = parser.parseTypeSig(sig);
        GenericsFactory factory = CoreReflectionFactory.make(container, ClassScope.make(container));
        Reifier reify = Reifier.make(factory);
        typeSig.accept(reify);
        Type result = reify.getResult();
        return toClass(result);
    }
    static Class toClass(Type o) {
        if (o instanceof GenericArrayType)
            return Array.newInstance(toClass(((GenericArrayType)o).getGenericComponentType()),
                                     0)
                .getClass();
        return (Class)o;
    }

    
Parses the enum constant member value at the current position in the specified byte buffer, resolving constant references in the specified constant pool. The cursor of the byte buffer must point to a "enum_const_value structure" as described in the RuntimeVisibleAnnotations_attribute: { u2 type_name_index; u2 const_name_index; } enum_const_value;
    private static Object parseEnumValue(Class enumTypeByteBuffer buf,
                                         ConstantPool constPool,
                                         Class container) {
        int typeNameIndex = buf.getShort() & 0xFFFF;
        String typeName  = constPool.getUTF8At(typeNameIndex);
        int constNameIndex = buf.getShort() & 0xFFFF;
        String constName = constPool.getUTF8At(constNameIndex);
        if (!typeName.endsWith(";")) {
            // support now-obsolete early jsr175-format class files.
            if (!enumType.getName().equals(typeName))
            return new AnnotationTypeMismatchExceptionProxy(
                typeName + "." + constName);
        } else if (enumType != parseSig(typeNamecontainer)) {
            return new AnnotationTypeMismatchExceptionProxy(
                typeName + "." + constName);
        }
        try {
            return  Enum.valueOf(enumTypeconstName);
        } catch(IllegalArgumentException e) {
            return new EnumConstantNotPresentExceptionProxy(
                (Class<? extends Enum>)enumTypeconstName);
        }
    }

    
Parses the array value at the current position in the specified byte buffer, resolving constant references in the specified constant pool. The cursor of the byte buffer must point to an array value struct as specified in the RuntimeVisibleAnnotations_attribute: { u2 num_values; member_value values[num_values]; } array_value; If the array values do not match arrayType, an AnnotationTypeMismatchExceptionProxy will be returned.
    private static Object parseArray(Class arrayType,
                                     ByteBuffer buf,
                                     ConstantPool constPool,
                                     Class container) {
        int length = buf.getShort() & 0xFFFF;  // Number of array components
        Class componentType = arrayType.getComponentType();
        if (componentType == byte.class) {
            return parseByteArray(lengthbufconstPool);
        } else if (componentType == char.class) {
            return parseCharArray(lengthbufconstPool);
        } else if (componentType == double.class) {
            return parseDoubleArray(lengthbufconstPool);
        } else if (componentType == float.class) {
            return parseFloatArray(lengthbufconstPool);
        } else if (componentType == int.class) {
            return parseIntArray(lengthbufconstPool);
        } else if (componentType == long.class) {
            return parseLongArray(lengthbufconstPool);
        } else if (componentType == short.class) {
            return parseShortArray(lengthbufconstPool);
        } else if (componentType == boolean.class) {
            return parseBooleanArray(lengthbufconstPool);
        } else if (componentType == String.class) {
            return parseStringArray(lengthbufconstPool);
        } else if (componentType == Class.class) {
            return parseClassArray(lengthbufconstPoolcontainer);
        } else if (componentType.isEnum()) {
            return parseEnumArray(lengthcomponentTypebuf,
                                  constPoolcontainer);
        } else {
            assert componentType.isAnnotation();
            return parseAnnotationArray(lengthcomponentTypebuf,
                                        constPoolcontainer);
        }
    }
    private static Object parseByteArray(int length,
                                  ByteBuffer bufConstantPool constPool) {
        byte[] result = new byte[length];
        boolean typeMismatch = false;
        int tag = 0;
        for (int i = 0; i < lengthi++) {
            tag = buf.get();
            if (tag == 'B') {
                int index = buf.getShort() & 0xFFFF;
                result[i] = (byteconstPool.getIntAt(index);
            } else {
                skipMemberValue(tagbuf);
                typeMismatch = true;
            }
        }
        return typeMismatch ? exceptionProxy(tag) : result;
    }
    private static Object parseCharArray(int length,
                                  ByteBuffer bufConstantPool constPool) {
        char[] result = new char[length];
        boolean typeMismatch = false;
        byte tag = 0;
        for (int i = 0; i < lengthi++) {
            tag = buf.get();
            if (tag == 'C') {
                int index = buf.getShort() & 0xFFFF;
                result[i] = (charconstPool.getIntAt(index);
            } else {
                skipMemberValue(tagbuf);
                typeMismatch = true;
            }
        }
        return typeMismatch ? exceptionProxy(tag) : result;
    }
    private static Object parseDoubleArray(int length,
                                    ByteBuffer bufConstantPool constPool) {
        double[] result = new  double[length];
        boolean typeMismatch = false;
        int tag = 0;
        for (int i = 0; i < lengthi++) {
            tag = buf.get();
            if (tag == 'D') {
                int index = buf.getShort() & 0xFFFF;
                result[i] = constPool.getDoubleAt(index);
            } else {
                skipMemberValue(tagbuf);
                typeMismatch = true;
            }
        }
        return typeMismatch ? exceptionProxy(tag) : result;
    }
    private static Object parseFloatArray(int length,
                                   ByteBuffer bufConstantPool constPool) {
        float[] result = new float[length];
        boolean typeMismatch = false;
        int tag = 0;
        for (int i = 0; i < lengthi++) {
            tag = buf.get();
            if (tag == 'F') {
                int index = buf.getShort() & 0xFFFF;
                result[i] = constPool.getFloatAt(index);
            } else {
                skipMemberValue(tagbuf);
                typeMismatch = true;
            }
        }
        return typeMismatch ? exceptionProxy(tag) : result;
    }
    private static Object parseIntArray(int length,
                                 ByteBuffer bufConstantPool constPool) {
        int[] result = new  int[length];
        boolean typeMismatch = false;
        int tag = 0;
        for (int i = 0; i < lengthi++) {
            tag = buf.get();
            if (tag == 'I') {
                int index = buf.getShort() & 0xFFFF;
                result[i] = constPool.getIntAt(index);
            } else {
                skipMemberValue(tagbuf);
                typeMismatch = true;
            }
        }
        return typeMismatch ? exceptionProxy(tag) : result;
    }
    private static Object parseLongArray(int length,
                                  ByteBuffer bufConstantPool constPool) {
        long[] result = new long[length];
        boolean typeMismatch = false;
        int tag = 0;
        for (int i = 0; i < lengthi++) {
            tag = buf.get();
            if (tag == 'J') {
                int index = buf.getShort() & 0xFFFF;
                result[i] = constPool.getLongAt(index);
            } else {
                skipMemberValue(tagbuf);
                typeMismatch = true;
            }
        }
        return typeMismatch ? exceptionProxy(tag) : result;
    }
    private static Object parseShortArray(int length,
                                   ByteBuffer bufConstantPool constPool) {
        short[] result = new short[length];
        boolean typeMismatch = false;
        int tag = 0;
        for (int i = 0; i < lengthi++) {
            tag = buf.get();
            if (tag == 'S') {
                int index = buf.getShort() & 0xFFFF;
                result[i] = (shortconstPool.getIntAt(index);
            } else {
                skipMemberValue(tagbuf);
                typeMismatch = true;
            }
        }
        return typeMismatch ? exceptionProxy(tag) : result;
    }
    private static Object parseBooleanArray(int length,
                                     ByteBuffer bufConstantPool constPool) {
        boolean[] result = new boolean[length];
        boolean typeMismatch = false;
        int tag = 0;
        for (int i = 0; i < lengthi++) {
            tag = buf.get();
            if (tag == 'Z') {
                int index = buf.getShort() & 0xFFFF;
                result[i] = (constPool.getIntAt(index) != 0);
            } else {
                skipMemberValue(tagbuf);
                typeMismatch = true;
            }
        }
        return typeMismatch ? exceptionProxy(tag) : result;
    }
    private static Object parseStringArray(int length,
                                    ByteBuffer buf,  ConstantPool constPool) {
        String[] result = new String[length];
        boolean typeMismatch = false;
        int tag = 0;
        for (int i = 0; i < lengthi++) {
            tag = buf.get();
            if (tag == 's') {
                int index = buf.getShort() & 0xFFFF;
                result[i] = constPool.getUTF8At(index);
            } else {
                skipMemberValue(tagbuf);
                typeMismatch = true;
            }
        }
        return typeMismatch ? exceptionProxy(tag) : result;
    }
    private static Object parseClassArray(int length,
                                          ByteBuffer buf,
                                          ConstantPool constPool,
                                          Class container) {
        Object[] result = new Class[length];
        boolean typeMismatch = false;
        int tag = 0;
        for (int i = 0; i < lengthi++) {
            tag = buf.get();
            if (tag == 'c') {
                result[i] = parseClassValue(bufconstPoolcontainer);
            } else {
                skipMemberValue(tagbuf);
                typeMismatch = true;
            }
        }
        return typeMismatch ? exceptionProxy(tag) : result;
    }
    private static Object parseEnumArray(int lengthClass enumType,
                                         ByteBuffer buf,
                                         ConstantPool constPool,
                                         Class container) {
        Object[] result = (Object[]) Array.newInstance(enumTypelength);
        boolean typeMismatch = false;
        int tag = 0;
        for (int i = 0; i < lengthi++) {
            tag = buf.get();
            if (tag == 'e') {
                result[i] = parseEnumValue(enumTypebufconstPoolcontainer);
            } else {
                skipMemberValue(tagbuf);
                typeMismatch = true;
            }
        }
        return typeMismatch ? exceptionProxy(tag) : result;
    }
    private static Object parseAnnotationArray(int length,
                                               Class annotationType,
                                               ByteBuffer buf,
                                               ConstantPool constPool,
                                               Class container) {
        Object[] result = (Object[]) Array.newInstance(annotationTypelength);
        boolean typeMismatch = false;
        int tag = 0;
        for (int i = 0; i < lengthi++) {
            tag = buf.get();
            if (tag == '@') {
                result[i] = parseAnnotation(bufconstPoolcontainertrue);
            } else {
                skipMemberValue(tagbuf);
                typeMismatch = true;
            }
        }
        return typeMismatch ? exceptionProxy(tag) : result;
    }

    
Return an appropriate exception proxy for a mismatching array annotation where the erroneous array has the specified tag.
    private static ExceptionProxy exceptionProxy(int tag) {
        return new AnnotationTypeMismatchExceptionProxy(
            "Array with component tag: " + tag);
    }

    
Skips the annotation at the current position in the specified byte buffer. The cursor of the byte buffer must point to an "annotation structure" OR two bytes into an annotation structure (i.e., after the type index).

Parameter:
complete true if the byte buffer points to the beginning of an annotation structure (rather than two bytes in).
    private static void skipAnnotation(ByteBuffer bufboolean complete) {
        if (complete)
            buf.getShort();   // Skip type index
        int numMembers = buf.getShort() & 0xFFFF;
        for (int i = 0; i < numMembersi++) {
            buf.getShort();   // Skip memberNameIndex
            skipMemberValue(buf);
        }
    }

    
Skips the annotation member value at the current position in the specified byte buffer. The cursor of the byte buffer must point to a "member_value structure."
    private static void skipMemberValue(ByteBuffer buf) {
        int tag = buf.get();
        skipMemberValue(tagbuf);
    }

    
Skips the annotation member value at the current position in the specified byte buffer. The cursor of the byte buffer must point immediately after the tag in a "member_value structure."
    private static void skipMemberValue(int tagByteBuffer buf) {
        switch(tag) {
          case 'e'// Enum value
            buf.getInt();  // (Two shorts, actually.)
            break;
          case '@':
            skipAnnotation(buftrue);
            break;
          case '[':
            skipArray(buf);
            break;
          default:
            // Class, primitive, or String
            buf.getShort();
        }
    }

    
Skips the array value at the current position in the specified byte buffer. The cursor of the byte buffer must point to an array value struct.
    private static void skipArray(ByteBuffer buf) {
        int length = buf.getShort() & 0xFFFF;
        for (int i = 0; i < lengthi++)
            skipMemberValue(buf);
    }
New to GrepCode? Check out our FAQ X