jodd-proxetta/src/main/java/jodd/asm7/ClassReader.java
private int readField(
      final ClassVisitor classVisitor, final Context context, final int fieldInfoOffset) {
    char[] charBuffer = context.charBuffer;

    // Read the access_flags, name_index and descriptor_index fields.
    int currentOffset = fieldInfoOffset;
    int accessFlags = readUnsignedShort(currentOffset);
    String name = readUTF8(currentOffset + 2, charBuffer);
    String descriptor = readUTF8(currentOffset + 4, charBuffer);
    currentOffset += 6;

    // Read the field attributes (the variables are ordered as in Section 4.7 of the JVMS).
    // Attribute offsets exclude the attribute_name_index and attribute_length fields.
    // - The value corresponding to the ConstantValue attribute, or null.
    Object constantValue = null;
    // - The string corresponding to the Signature attribute, or null.
    String signature = null;
    // - The offset of the RuntimeVisibleAnnotations attribute, or 0.
    int runtimeVisibleAnnotationsOffset = 0;
    // - The offset of the RuntimeInvisibleAnnotations attribute, or 0.
    int runtimeInvisibleAnnotationsOffset = 0;
    // - The offset of the RuntimeVisibleTypeAnnotations attribute, or 0.
    int runtimeVisibleTypeAnnotationsOffset = 0;
    // - The offset of the RuntimeInvisibleTypeAnnotations attribute, or 0.
    int runtimeInvisibleTypeAnnotationsOffset = 0;
    // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field).
    //   This list in the <i>reverse order</i> or their order in the ClassFile structure.
    Attribute attributes = null;

    int attributesCount = readUnsignedShort(currentOffset);
    currentOffset += 2;
    while (attributesCount-- > 0) {
      // Read the attribute_info's attribute_name and attribute_length fields.
      String attributeName = readUTF8(currentOffset, charBuffer);
      int attributeLength = readInt(currentOffset + 2);
      currentOffset += 6;
      // The tests are sorted in decreasing frequency order (based on frequencies observed on
      // typical classes).
      if (Constants.CONSTANT_VALUE.equals(attributeName)) {
        int constantvalueIndex = readUnsignedShort(currentOffset);
        constantValue = constantvalueIndex == 0 ? null : readConst(constantvalueIndex, charBuffer);
      } else if (Constants.SIGNATURE.equals(attributeName)) {
        signature = readUTF8(currentOffset, charBuffer);
      } else if (Constants.DEPRECATED.equals(attributeName)) {
        accessFlags |= Opcodes.ACC_DEPRECATED;
      } else if (Constants.SYNTHETIC.equals(attributeName)) {
        accessFlags |= Opcodes.ACC_SYNTHETIC;
      } else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) {
        runtimeVisibleAnnotationsOffset = currentOffset;
      } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
        runtimeVisibleTypeAnnotationsOffset = currentOffset;
      } else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) {
        runtimeInvisibleAnnotationsOffset = currentOffset;
      } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
        runtimeInvisibleTypeAnnotationsOffset = currentOffset;
      } else {
        Attribute attribute =
            readAttribute(
                context.attributePrototypes,
                attributeName,
                currentOffset,
                attributeLength,
                charBuffer,
                -1,
                null);
        attribute.nextAttribute = attributes;
        attributes = attribute;
      }
      currentOffset += attributeLength;
    }

    // Visit the field declaration.
    FieldVisitor fieldVisitor =
        classVisitor.visitField(accessFlags, name, descriptor, signature, constantValue);
    if (fieldVisitor == null) {
      return currentOffset;
    }

    // Visit the RuntimeVisibleAnnotations attribute.
    if (runtimeVisibleAnnotationsOffset != 0) {
      int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset);
      int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2;
      while (numAnnotations-- > 0) {
        // Parse the type_index field.
        String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
        currentAnnotationOffset += 2;
        // Parse num_element_value_pairs and element_value_pairs and visit these values.
        currentAnnotationOffset =
            readElementValues(
                fieldVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true),
                currentAnnotationOffset,
                /* named = */ true,
                charBuffer);
      }
    }

    // Visit the RuntimeInvisibleAnnotations attribute.
    if (runtimeInvisibleAnnotationsOffset != 0) {
      int numAnnotations = readUnsignedShort(runtimeInvisibleAnnotationsOffset);
      int currentAnnotationOffset = runtimeInvisibleAnnotationsOffset + 2;
      while (numAnnotations-- > 0) {
        // Parse the type_index field.
        String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
        currentAnnotationOffset += 2;
        // Parse num_element_value_pairs and element_value_pairs and visit these values.
        currentAnnotationOffset =
            readElementValues(
                fieldVisitor.visitAnnotation(annotationDescriptor, /* visible = */ false),
                currentAnnotationOffset,
                /* named = */ true,
                charBuffer);
      }
    }

    // Visit the RuntimeVisibleTypeAnnotations attribute.
    if (runtimeVisibleTypeAnnotationsOffset != 0) {
      int numAnnotations = readUnsignedShort(runtimeVisibleTypeAnnotationsOffset);
      int currentAnnotationOffset = runtimeVisibleTypeAnnotationsOffset + 2;
      while (numAnnotations-- > 0) {
        // Parse the target_type, target_info and target_path fields.
        currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset);
        // Parse the type_index field.
        String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
        currentAnnotationOffset += 2;
        // Parse num_element_value_pairs and element_value_pairs and visit these values.
        currentAnnotationOffset =
            readElementValues(
                fieldVisitor.visitTypeAnnotation(
                    context.currentTypeAnnotationTarget,
                    context.currentTypeAnnotationTargetPath,
                    annotationDescriptor,
                    /* visible = */ true),
                currentAnnotationOffset,
                /* named = */ true,
                charBuffer);
      }
    }

    // Visit the RuntimeInvisibleTypeAnnotations attribute.
    if (runtimeInvisibleTypeAnnotationsOffset != 0) {
      int numAnnotations = readUnsignedShort(runtimeInvisibleTypeAnnotationsOffset);
      int currentAnnotationOffset = runtimeInvisibleTypeAnnotationsOffset + 2;
      while (numAnnotations-- > 0) {
        // Parse the target_type, target_info and target_path fields.
        currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset);
        // Parse the type_index field.
        String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
        currentAnnotationOffset += 2;
        // Parse num_element_value_pairs and element_value_pairs and visit these values.
        currentAnnotationOffset =
            readElementValues(
                fieldVisitor.visitTypeAnnotation(
                    context.currentTypeAnnotationTarget,
                    context.currentTypeAnnotationTargetPath,
                    annotationDescriptor,
                    /* visible = */ false),
                currentAnnotationOffset,
                /* named = */ true,
                charBuffer);
      }
    }

    // Visit the non standard attributes.
    while (attributes != null) {
      // Copy and reset the nextAttribute field so that it can also be used in FieldWriter.
      Attribute nextAttribute = attributes.nextAttribute;
      attributes.nextAttribute = null;
      fieldVisitor.visitAttribute(attributes);
      attributes = nextAttribute;
    }

    // Visit the end of the field.
    fieldVisitor.visitEnd();
    return currentOffset;
  }
private int readField(
      final ClassVisitor classVisitor, final Context context, final int fieldInfoOffset) {
    char[] charBuffer = context.charBuffer;

    // Read the access_flags, name_index and descriptor_index fields.
    int currentOffset = fieldInfoOffset;
    int accessFlags = readUnsignedShort(currentOffset);
    String name = readUTF8(currentOffset + 2, charBuffer);
    String descriptor = readUTF8(currentOffset + 4, charBuffer);
    currentOffset += 6;

    // Read the field attributes (the variables are ordered as in Section 4.7 of the JVMS).
    // Attribute offsets exclude the attribute_name_index and attribute_length fields.
    // - The value corresponding to the ConstantValue attribute, or null.
    Object constantValue = null;
    // - The string corresponding to the Signature attribute, or null.
    String signature = null;
    // - The offset of the RuntimeVisibleAnnotations attribute, or 0.
    int runtimeVisibleAnnotationsOffset = 0;
    // - The offset of the RuntimeInvisibleAnnotations attribute, or 0.
    int runtimeInvisibleAnnotationsOffset = 0;
    // - The offset of the RuntimeVisibleTypeAnnotations attribute, or 0.
    int runtimeVisibleTypeAnnotationsOffset = 0;
    // - The offset of the RuntimeInvisibleTypeAnnotations attribute, or 0.
    int runtimeInvisibleTypeAnnotationsOffset = 0;
    // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field).
    //   This list in the <i>reverse order</i> or their order in the ClassFile structure.
    Attribute attributes = null;

    int attributesCount = readUnsignedShort(currentOffset);
    currentOffset += 2;
    while (attributesCount-- > 0) {
      // Read the attribute_info's attribute_name and attribute_length fields.
      String attributeName = readUTF8(currentOffset, charBuffer);
      int attributeLength = readInt(currentOffset + 2);
      currentOffset += 6;
      // The tests are sorted in decreasing frequency order (based on frequencies observed on
      // typical classes).
      if (Constants.CONSTANT_VALUE.equals(attributeName)) {
        int constantvalueIndex = readUnsignedShort(currentOffset);
        constantValue = constantvalueIndex == 0 ? null : readConst(constantvalueIndex, charBuffer);
      } else if (Constants.SIGNATURE.equals(attributeName)) {
        signature = readUTF8(currentOffset, charBuffer);
      } else if (Constants.DEPRECATED.equals(attributeName)) {
        accessFlags |= Opcodes.ACC_DEPRECATED;
      } else if (Constants.SYNTHETIC.equals(attributeName)) {
        accessFlags |= Opcodes.ACC_SYNTHETIC;
      } else if (Constants.RUNTIME_VISIBLE_ANNOTATIONS.equals(attributeName)) {
        runtimeVisibleAnnotationsOffset = currentOffset;
      } else if (Constants.RUNTIME_VISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
        runtimeVisibleTypeAnnotationsOffset = currentOffset;
      } else if (Constants.RUNTIME_INVISIBLE_ANNOTATIONS.equals(attributeName)) {
        runtimeInvisibleAnnotationsOffset = currentOffset;
      } else if (Constants.RUNTIME_INVISIBLE_TYPE_ANNOTATIONS.equals(attributeName)) {
        runtimeInvisibleTypeAnnotationsOffset = currentOffset;
      } else {
        Attribute attribute =
            readAttribute(
                context.attributePrototypes,
                attributeName,
                currentOffset,
                attributeLength,
                charBuffer,
                -1,
                null);
        attribute.nextAttribute = attributes;
        attributes = attribute;
      }
      currentOffset += attributeLength;
    }

    // Visit the field declaration.
    FieldVisitor fieldVisitor =
        classVisitor.visitField(accessFlags, name, descriptor, signature, constantValue);
    if (fieldVisitor == null) {
      return currentOffset;
    }

    // Visit the RuntimeVisibleAnnotations attribute.
    if (runtimeVisibleAnnotationsOffset != 0) {
      int numAnnotations = readUnsignedShort(runtimeVisibleAnnotationsOffset);
      int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2;
      while (numAnnotations-- > 0) {
        // Parse the type_index field.
        String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
        currentAnnotationOffset += 2;
        // Parse num_element_value_pairs and element_value_pairs and visit these values.
        currentAnnotationOffset =
            readElementValues(
                fieldVisitor.visitAnnotation(annotationDescriptor, /* visible = */ true),
                currentAnnotationOffset,
                /* named = */ true,
                charBuffer);
      }
    }

    // Visit the RuntimeInvisibleAnnotations attribute.
    if (runtimeInvisibleAnnotationsOffset != 0) {
      int numAnnotations = readUnsignedShort(runtimeInvisibleAnnotationsOffset);
      int currentAnnotationOffset = runtimeInvisibleAnnotationsOffset + 2;
      while (numAnnotations-- > 0) {
        // Parse the type_index field.
        String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
        currentAnnotationOffset += 2;
        // Parse num_element_value_pairs and element_value_pairs and visit these values.
        currentAnnotationOffset =
            readElementValues(
                fieldVisitor.visitAnnotation(annotationDescriptor, /* visible = */ false),
                currentAnnotationOffset,
                /* named = */ true,
                charBuffer);
      }
    }

    // Visit the RuntimeVisibleTypeAnnotations attribute.
    if (runtimeVisibleTypeAnnotationsOffset != 0) {
      int numAnnotations = readUnsignedShort(runtimeVisibleTypeAnnotationsOffset);
      int currentAnnotationOffset = runtimeVisibleTypeAnnotationsOffset + 2;
      while (numAnnotations-- > 0) {
        // Parse the target_type, target_info and target_path fields.
        currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset);
        // Parse the type_index field.
        String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
        currentAnnotationOffset += 2;
        // Parse num_element_value_pairs and element_value_pairs and visit these values.
        currentAnnotationOffset =
            readElementValues(
                fieldVisitor.visitTypeAnnotation(
                    context.currentTypeAnnotationTarget,
                    context.currentTypeAnnotationTargetPath,
                    annotationDescriptor,
                    /* visible = */ true),
                currentAnnotationOffset,
                /* named = */ true,
                charBuffer);
      }
    }

    // Visit the RuntimeInvisibleTypeAnnotations attribute.
    if (runtimeInvisibleTypeAnnotationsOffset != 0) {
      int numAnnotations = readUnsignedShort(runtimeInvisibleTypeAnnotationsOffset);
      int currentAnnotationOffset = runtimeInvisibleTypeAnnotationsOffset + 2;
      while (numAnnotations-- > 0) {
        // Parse the target_type, target_info and target_path fields.
        currentAnnotationOffset = readTypeAnnotationTarget(context, currentAnnotationOffset);
        // Parse the type_index field.
        String annotationDescriptor = readUTF8(currentAnnotationOffset, charBuffer);
        currentAnnotationOffset += 2;
        // Parse num_element_value_pairs and element_value_pairs and visit these values.
        currentAnnotationOffset =
            readElementValues(
                fieldVisitor.visitTypeAnnotation(
                    context.currentTypeAnnotationTarget,
                    context.currentTypeAnnotationTargetPath,
                    annotationDescriptor,
                    /* visible = */ false),
                currentAnnotationOffset,
                /* named = */ true,
                charBuffer);
      }
    }

    // Visit the non standard attributes.
    while (attributes != null) {
      // Copy and reset the nextAttribute field so that it can also be used in FieldWriter.
      Attribute nextAttribute = attributes.nextAttribute;
      attributes.nextAttribute = null;
      fieldVisitor.visitAttribute(attributes);
      attributes = nextAttribute;
    }

    // Visit the end of the field.
    fieldVisitor.visitEnd();
    return currentOffset;
  }
private int readField ( final ClassVisitor classVisitor , final Context context , final int fieldInfoOffset ) { char [ ] charBuffer = context . charBuffer ; // Read the access_flags, name_index and descriptor_index fields. int currentOffset = fieldInfoOffset ; int accessFlags = readUnsignedShort ( currentOffset ) ; String name = readUTF8 ( currentOffset + 2 , charBuffer ) ; String descriptor = readUTF8 ( currentOffset + 4 , charBuffer ) ; currentOffset += 6 ; // Read the field attributes (the variables are ordered as in Section 4.7 of the JVMS). // Attribute offsets exclude the attribute_name_index and attribute_length fields. // - The value corresponding to the ConstantValue attribute, or null. Object constantValue = null ; // - The string corresponding to the Signature attribute, or null. String signature = null ; // - The offset of the RuntimeVisibleAnnotations attribute, or 0. int runtimeVisibleAnnotationsOffset = 0 ; // - The offset of the RuntimeInvisibleAnnotations attribute, or 0. int runtimeInvisibleAnnotationsOffset = 0 ; // - The offset of the RuntimeVisibleTypeAnnotations attribute, or 0. int runtimeVisibleTypeAnnotationsOffset = 0 ; // - The offset of the RuntimeInvisibleTypeAnnotations attribute, or 0. int runtimeInvisibleTypeAnnotationsOffset = 0 ; // - The non standard attributes (linked with their {@link Attribute#nextAttribute} field). //   This list in the <i>reverse order</i> or their order in the ClassFile structure. Attribute attributes = null ; int attributesCount = readUnsignedShort ( currentOffset ) ; currentOffset += 2 ; while ( attributesCount -- > 0 ) { // Read the attribute_info's attribute_name and attribute_length fields. String attributeName = readUTF8 ( currentOffset , charBuffer ) ; int attributeLength = readInt ( currentOffset + 2 ) ; currentOffset += 6 ; // The tests are sorted in decreasing frequency order (based on frequencies observed on // typical classes). if ( Constants . CONSTANT_VALUE . equals ( attributeName ) ) { int constantvalueIndex = readUnsignedShort ( currentOffset ) ; constantValue = constantvalueIndex == 0 ? null : readConst ( constantvalueIndex , charBuffer ) ; } else if ( Constants . SIGNATURE . equals ( attributeName ) ) { signature = readUTF8 ( currentOffset , charBuffer ) ; } else if ( Constants . DEPRECATED . equals ( attributeName ) ) { accessFlags |= Opcodes . ACC_DEPRECATED ; } else if ( Constants . SYNTHETIC . equals ( attributeName ) ) { accessFlags |= Opcodes . ACC_SYNTHETIC ; } else if ( Constants . RUNTIME_VISIBLE_ANNOTATIONS . equals ( attributeName ) ) { runtimeVisibleAnnotationsOffset = currentOffset ; } else if ( Constants . RUNTIME_VISIBLE_TYPE_ANNOTATIONS . equals ( attributeName ) ) { runtimeVisibleTypeAnnotationsOffset = currentOffset ; } else if ( Constants . RUNTIME_INVISIBLE_ANNOTATIONS . equals ( attributeName ) ) { runtimeInvisibleAnnotationsOffset = currentOffset ; } else if ( Constants . RUNTIME_INVISIBLE_TYPE_ANNOTATIONS . equals ( attributeName ) ) { runtimeInvisibleTypeAnnotationsOffset = currentOffset ; } else { Attribute attribute = readAttribute ( context . attributePrototypes , attributeName , currentOffset , attributeLength , charBuffer , - 1 , null ) ; attribute . nextAttribute = attributes ; attributes = attribute ; } currentOffset += attributeLength ; } // Visit the field declaration. FieldVisitor fieldVisitor = classVisitor . visitField ( accessFlags , name , descriptor , signature , constantValue ) ; if ( fieldVisitor == null ) { return currentOffset ; } // Visit the RuntimeVisibleAnnotations attribute. if ( runtimeVisibleAnnotationsOffset != 0 ) { int numAnnotations = readUnsignedShort ( runtimeVisibleAnnotationsOffset ) ; int currentAnnotationOffset = runtimeVisibleAnnotationsOffset + 2 ; while ( numAnnotations -- > 0 ) { // Parse the type_index field. String annotationDescriptor = readUTF8 ( currentAnnotationOffset , charBuffer ) ; currentAnnotationOffset += 2 ; // Parse num_element_value_pairs and element_value_pairs and visit these values. currentAnnotationOffset = readElementValues ( fieldVisitor . visitAnnotation ( annotationDescriptor , /* visible = */ true ) , currentAnnotationOffset , /* named = */ true , charBuffer ) ; } } // Visit the RuntimeInvisibleAnnotations attribute. if ( runtimeInvisibleAnnotationsOffset != 0 ) { int numAnnotations = readUnsignedShort ( runtimeInvisibleAnnotationsOffset ) ; int currentAnnotationOffset = runtimeInvisibleAnnotationsOffset + 2 ; while ( numAnnotations -- > 0 ) { // Parse the type_index field. String annotationDescriptor = readUTF8 ( currentAnnotationOffset , charBuffer ) ; currentAnnotationOffset += 2 ; // Parse num_element_value_pairs and element_value_pairs and visit these values. currentAnnotationOffset = readElementValues ( fieldVisitor . visitAnnotation ( annotationDescriptor , /* visible = */ false ) , currentAnnotationOffset , /* named = */ true , charBuffer ) ; } } // Visit the RuntimeVisibleTypeAnnotations attribute. if ( runtimeVisibleTypeAnnotationsOffset != 0 ) { int numAnnotations = readUnsignedShort ( runtimeVisibleTypeAnnotationsOffset ) ; int currentAnnotationOffset = runtimeVisibleTypeAnnotationsOffset + 2 ; while ( numAnnotations -- > 0 ) { // Parse the target_type, target_info and target_path fields. currentAnnotationOffset = readTypeAnnotationTarget ( context , currentAnnotationOffset ) ; // Parse the type_index field. String annotationDescriptor = readUTF8 ( currentAnnotationOffset , charBuffer ) ; currentAnnotationOffset += 2 ; // Parse num_element_value_pairs and element_value_pairs and visit these values. currentAnnotationOffset = readElementValues ( fieldVisitor . visitTypeAnnotation ( context . currentTypeAnnotationTarget , context . currentTypeAnnotationTargetPath , annotationDescriptor , /* visible = */ true ) , currentAnnotationOffset , /* named = */ true , charBuffer ) ; } } // Visit the RuntimeInvisibleTypeAnnotations attribute. if ( runtimeInvisibleTypeAnnotationsOffset != 0 ) { int numAnnotations = readUnsignedShort ( runtimeInvisibleTypeAnnotationsOffset ) ; int currentAnnotationOffset = runtimeInvisibleTypeAnnotationsOffset + 2 ; while ( numAnnotations -- > 0 ) { // Parse the target_type, target_info and target_path fields. currentAnnotationOffset = readTypeAnnotationTarget ( context , currentAnnotationOffset ) ; // Parse the type_index field. String annotationDescriptor = readUTF8 ( currentAnnotationOffset , charBuffer ) ; currentAnnotationOffset += 2 ; // Parse num_element_value_pairs and element_value_pairs and visit these values. currentAnnotationOffset = readElementValues ( fieldVisitor . visitTypeAnnotation ( context . currentTypeAnnotationTarget , context . currentTypeAnnotationTargetPath , annotationDescriptor , /* visible = */ false ) , currentAnnotationOffset , /* named = */ true , charBuffer ) ; } } // Visit the non standard attributes. while ( attributes != null ) { // Copy and reset the nextAttribute field so that it can also be used in FieldWriter. Attribute nextAttribute = attributes . nextAttribute ; attributes . nextAttribute = null ; fieldVisitor . visitAttribute ( attributes ) ; attributes = nextAttribute ; } // Visit the end of the field. fieldVisitor . visitEnd ( ) ; return currentOffset ; }
Reads a JVMS field_info structure and makes the given visitor visit it.

@param classVisitor the visitor that must visit the field.
@param context information about the class being parsed.
@param fieldInfoOffset the start offset of the field_info structure.
@return the offset of the first byte following the field_info structure.
Reads a JVMS field_info structure and makes the given visitor visit it .