jodd-proxetta/src/main/java/jodd/asm7/ClassReader.java
private int[] readTypeAnnotations(
      final MethodVisitor methodVisitor,
      final Context context,
      final int runtimeTypeAnnotationsOffset,
      final boolean visible) {
    char[] charBuffer = context.charBuffer;
    int currentOffset = runtimeTypeAnnotationsOffset;
    // Read the num_annotations field and create an array to store the type_annotation offsets.
    int[] typeAnnotationsOffsets = new int[readUnsignedShort(currentOffset)];
    currentOffset += 2;
    // Parse the 'annotations' array field.
    for (int i = 0; i < typeAnnotationsOffsets.length; ++i) {
      typeAnnotationsOffsets[i] = currentOffset;
      // Parse the type_annotation's target_type and the target_info fields. The size of the
      // target_info field depends on the value of target_type.
      int targetType = readInt(currentOffset);
      switch (targetType >>> 24) {
        case TypeReference.LOCAL_VARIABLE:
        case TypeReference.RESOURCE_VARIABLE:
          // A localvar_target has a variable size, which depends on the value of their table_length
          // field. It also references bytecode offsets, for which we need labels.
          int tableLength = readUnsignedShort(currentOffset + 1);
          currentOffset += 3;
          while (tableLength-- > 0) {
            int startPc = readUnsignedShort(currentOffset);
            int length = readUnsignedShort(currentOffset + 2);
            // Skip the index field (2 bytes).
            currentOffset += 6;
            createLabel(startPc, context.currentMethodLabels);
            createLabel(startPc + length, context.currentMethodLabels);
          }
          break;
        case TypeReference.CAST:
        case TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
        case TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT:
        case TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
        case TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT:
          currentOffset += 4;
          break;
        case TypeReference.CLASS_EXTENDS:
        case TypeReference.CLASS_TYPE_PARAMETER_BOUND:
        case TypeReference.METHOD_TYPE_PARAMETER_BOUND:
        case TypeReference.THROWS:
        case TypeReference.EXCEPTION_PARAMETER:
        case TypeReference.INSTANCEOF:
        case TypeReference.NEW:
        case TypeReference.CONSTRUCTOR_REFERENCE:
        case TypeReference.METHOD_REFERENCE:
          currentOffset += 3;
          break;
        case TypeReference.CLASS_TYPE_PARAMETER:
        case TypeReference.METHOD_TYPE_PARAMETER:
        case TypeReference.METHOD_FORMAL_PARAMETER:
        case TypeReference.FIELD:
        case TypeReference.METHOD_RETURN:
        case TypeReference.METHOD_RECEIVER:
        default:
          // TypeReference type which can't be used in Code attribute, or which is unknown.
          throw new IllegalArgumentException();
      }
      // Parse the rest of the type_annotation structure, starting with the target_path structure
      // (whose size depends on its path_length field).
      int pathLength = readByte(currentOffset);
      if ((targetType >>> 24) == TypeReference.EXCEPTION_PARAMETER) {
        // Parse the target_path structure and create a corresponding TypePath.
        TypePath path = pathLength == 0 ? null : new TypePath(b, currentOffset);
        currentOffset += 1 + 2 * pathLength;
        // Parse the type_index field.
        String annotationDescriptor = readUTF8(currentOffset, charBuffer);
        currentOffset += 2;
        // Parse num_element_value_pairs and element_value_pairs and visit these values.
        currentOffset =
            readElementValues(
                methodVisitor.visitTryCatchAnnotation(
                    targetType & 0xFFFFFF00, path, annotationDescriptor, visible),
                currentOffset,
                /* named = */ true,
                charBuffer);
      } else {
        // We don't want to visit the other target_type annotations, so we just skip them (which
        // requires some parsing because the element_value_pairs array has a variable size). First,
        // skip the target_path structure:
        currentOffset += 3 + 2 * pathLength;
        // Then skip the num_element_value_pairs and element_value_pairs fields (by reading them
        // with a null AnnotationVisitor).
        currentOffset =
            readElementValues(
                /* annotationVisitor = */ null, currentOffset, /* named = */ true, charBuffer);
      }
    }
    return typeAnnotationsOffsets;
  }
private int[] readTypeAnnotations(
      final MethodVisitor methodVisitor,
      final Context context,
      final int runtimeTypeAnnotationsOffset,
      final boolean visible) {
    char[] charBuffer = context.charBuffer;
    int currentOffset = runtimeTypeAnnotationsOffset;
    // Read the num_annotations field and create an array to store the type_annotation offsets.
    int[] typeAnnotationsOffsets = new int[readUnsignedShort(currentOffset)];
    currentOffset += 2;
    // Parse the 'annotations' array field.
    for (int i = 0; i < typeAnnotationsOffsets.length; ++i) {
      typeAnnotationsOffsets[i] = currentOffset;
      // Parse the type_annotation's target_type and the target_info fields. The size of the
      // target_info field depends on the value of target_type.
      int targetType = readInt(currentOffset);
      switch (targetType >>> 24) {
        case TypeReference.LOCAL_VARIABLE:
        case TypeReference.RESOURCE_VARIABLE:
          // A localvar_target has a variable size, which depends on the value of their table_length
          // field. It also references bytecode offsets, for which we need labels.
          int tableLength = readUnsignedShort(currentOffset + 1);
          currentOffset += 3;
          while (tableLength-- > 0) {
            int startPc = readUnsignedShort(currentOffset);
            int length = readUnsignedShort(currentOffset + 2);
            // Skip the index field (2 bytes).
            currentOffset += 6;
            createLabel(startPc, context.currentMethodLabels);
            createLabel(startPc + length, context.currentMethodLabels);
          }
          break;
        case TypeReference.CAST:
        case TypeReference.CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT:
        case TypeReference.METHOD_INVOCATION_TYPE_ARGUMENT:
        case TypeReference.CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT:
        case TypeReference.METHOD_REFERENCE_TYPE_ARGUMENT:
          currentOffset += 4;
          break;
        case TypeReference.CLASS_EXTENDS:
        case TypeReference.CLASS_TYPE_PARAMETER_BOUND:
        case TypeReference.METHOD_TYPE_PARAMETER_BOUND:
        case TypeReference.THROWS:
        case TypeReference.EXCEPTION_PARAMETER:
        case TypeReference.INSTANCEOF:
        case TypeReference.NEW:
        case TypeReference.CONSTRUCTOR_REFERENCE:
        case TypeReference.METHOD_REFERENCE:
          currentOffset += 3;
          break;
        case TypeReference.CLASS_TYPE_PARAMETER:
        case TypeReference.METHOD_TYPE_PARAMETER:
        case TypeReference.METHOD_FORMAL_PARAMETER:
        case TypeReference.FIELD:
        case TypeReference.METHOD_RETURN:
        case TypeReference.METHOD_RECEIVER:
        default:
          // TypeReference type which can't be used in Code attribute, or which is unknown.
          throw new IllegalArgumentException();
      }
      // Parse the rest of the type_annotation structure, starting with the target_path structure
      // (whose size depends on its path_length field).
      int pathLength = readByte(currentOffset);
      if ((targetType >>> 24) == TypeReference.EXCEPTION_PARAMETER) {
        // Parse the target_path structure and create a corresponding TypePath.
        TypePath path = pathLength == 0 ? null : new TypePath(b, currentOffset);
        currentOffset += 1 + 2 * pathLength;
        // Parse the type_index field.
        String annotationDescriptor = readUTF8(currentOffset, charBuffer);
        currentOffset += 2;
        // Parse num_element_value_pairs and element_value_pairs and visit these values.
        currentOffset =
            readElementValues(
                methodVisitor.visitTryCatchAnnotation(
                    targetType & 0xFFFFFF00, path, annotationDescriptor, visible),
                currentOffset,
                /* named = */ true,
                charBuffer);
      } else {
        // We don't want to visit the other target_type annotations, so we just skip them (which
        // requires some parsing because the element_value_pairs array has a variable size). First,
        // skip the target_path structure:
        currentOffset += 3 + 2 * pathLength;
        // Then skip the num_element_value_pairs and element_value_pairs fields (by reading them
        // with a null AnnotationVisitor).
        currentOffset =
            readElementValues(
                /* annotationVisitor = */ null, currentOffset, /* named = */ true, charBuffer);
      }
    }
    return typeAnnotationsOffsets;
  }
private int [ ] readTypeAnnotations ( final MethodVisitor methodVisitor , final Context context , final int runtimeTypeAnnotationsOffset , final boolean visible ) { char [ ] charBuffer = context . charBuffer ; int currentOffset = runtimeTypeAnnotationsOffset ; // Read the num_annotations field and create an array to store the type_annotation offsets. int [ ] typeAnnotationsOffsets = new int [ readUnsignedShort ( currentOffset ) ] ; currentOffset += 2 ; // Parse the 'annotations' array field. for ( int i = 0 ; i < typeAnnotationsOffsets . length ; ++ i ) { typeAnnotationsOffsets [ i ] = currentOffset ; // Parse the type_annotation's target_type and the target_info fields. The size of the // target_info field depends on the value of target_type. int targetType = readInt ( currentOffset ) ; switch ( targetType >>> 24 ) { case TypeReference . LOCAL_VARIABLE : case TypeReference . RESOURCE_VARIABLE : // A localvar_target has a variable size, which depends on the value of their table_length // field. It also references bytecode offsets, for which we need labels. int tableLength = readUnsignedShort ( currentOffset + 1 ) ; currentOffset += 3 ; while ( tableLength -- > 0 ) { int startPc = readUnsignedShort ( currentOffset ) ; int length = readUnsignedShort ( currentOffset + 2 ) ; // Skip the index field (2 bytes). currentOffset += 6 ; createLabel ( startPc , context . currentMethodLabels ) ; createLabel ( startPc + length , context . currentMethodLabels ) ; } break ; case TypeReference . CAST : case TypeReference . CONSTRUCTOR_INVOCATION_TYPE_ARGUMENT : case TypeReference . METHOD_INVOCATION_TYPE_ARGUMENT : case TypeReference . CONSTRUCTOR_REFERENCE_TYPE_ARGUMENT : case TypeReference . METHOD_REFERENCE_TYPE_ARGUMENT : currentOffset += 4 ; break ; case TypeReference . CLASS_EXTENDS : case TypeReference . CLASS_TYPE_PARAMETER_BOUND : case TypeReference . METHOD_TYPE_PARAMETER_BOUND : case TypeReference . THROWS : case TypeReference . EXCEPTION_PARAMETER : case TypeReference . INSTANCEOF : case TypeReference . NEW : case TypeReference . CONSTRUCTOR_REFERENCE : case TypeReference . METHOD_REFERENCE : currentOffset += 3 ; break ; case TypeReference . CLASS_TYPE_PARAMETER : case TypeReference . METHOD_TYPE_PARAMETER : case TypeReference . METHOD_FORMAL_PARAMETER : case TypeReference . FIELD : case TypeReference . METHOD_RETURN : case TypeReference . METHOD_RECEIVER : default : // TypeReference type which can't be used in Code attribute, or which is unknown. throw new IllegalArgumentException ( ) ; } // Parse the rest of the type_annotation structure, starting with the target_path structure // (whose size depends on its path_length field). int pathLength = readByte ( currentOffset ) ; if ( ( targetType >>> 24 ) == TypeReference . EXCEPTION_PARAMETER ) { // Parse the target_path structure and create a corresponding TypePath. TypePath path = pathLength == 0 ? null : new TypePath ( b , currentOffset ) ; currentOffset += 1 + 2 * pathLength ; // Parse the type_index field. String annotationDescriptor = readUTF8 ( currentOffset , charBuffer ) ; currentOffset += 2 ; // Parse num_element_value_pairs and element_value_pairs and visit these values. currentOffset = readElementValues ( methodVisitor . visitTryCatchAnnotation ( targetType & 0xFFFFFF00 , path , annotationDescriptor , visible ) , currentOffset , /* named = */ true , charBuffer ) ; } else { // We don't want to visit the other target_type annotations, so we just skip them (which // requires some parsing because the element_value_pairs array has a variable size). First, // skip the target_path structure: currentOffset += 3 + 2 * pathLength ; // Then skip the num_element_value_pairs and element_value_pairs fields (by reading them // with a null AnnotationVisitor). currentOffset = readElementValues ( /* annotationVisitor = */ null , currentOffset , /* named = */ true , charBuffer ) ; } } return typeAnnotationsOffsets ; }
Parses a Runtime[In]VisibleTypeAnnotations attribute to find the offset of each type_annotation
entry it contains, to find the corresponding labels, and to visit the try catch block
annotations.

@param methodVisitor the method visitor to be used to visit the try catch block annotations.
@param context information about the class being parsed.
@param runtimeTypeAnnotationsOffset the start offset of a Runtime[In]VisibleTypeAnnotations
attribute, excluding the attribute_info's attribute_name_index and attribute_length fields.
@param visible true if the attribute to parse is a RuntimeVisibleTypeAnnotations attribute,
false it is a RuntimeInvisibleTypeAnnotations attribute.
@return the start offset of each entry of the Runtime[In]VisibleTypeAnnotations_attribute's
'annotations' array field.
Parses a Runtime [ In ] VisibleTypeAnnotations attribute to find the offset of each type_annotation entry it contains to find the corresponding labels and to visit the try catch block annotations .