class StructInfo {
    final int modifiers;
    final boolean referenceDetect;
    final boolean smartMatch;

    String typeKey;
    int readerFeatures;
    int writerFeatures;
    final TypeElement element;
    final DeclaredType discoveredBy;
    final String name;
    final String binaryName;
    final Map<String, AttributeInfo> attributes = new LinkedHashMap<>();

    public StructInfo(
            Types types,
            TypeElement element,
            DeclaredType discoveredBy,
            String name,
            String binaryName
    ) {
        this.element = element;
        this.discoveredBy = discoveredBy;
        this.name = name;
        this.binaryName = binaryName;

        this.modifiers = Analysis.getModifiers(element.getModifiers());

        AnnotationMirror anntation = null;
        for (AnnotationMirror mirror : element.getAnnotationMirrors()) {
            if (types.isSameType(mirror.getAnnotationType(), discoveredBy)) {
                anntation = mirror;
            }
        }

        boolean referenceDetect = true, smartMatch = true;
        if (anntation != null) {
            for (Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> entry : anntation.getElementValues().entrySet()) {
                String annFieldName = entry.getKey().getSimpleName().toString();
                AnnotationValue value = entry.getValue();
                switch (annFieldName) {
                    case "referenceDetect":
                        referenceDetect = (Boolean) value.getValue();
                        break;
                    case "smartMatch":
                        smartMatch = (Boolean) value.getValue();
                        break;
                    default:
                        break;
                }
            }
        }
        this.referenceDetect = referenceDetect;
        this.smartMatch = smartMatch;
    }

    public AttributeInfo getAttributeByField(String name, VariableElement field) {
        AttributeInfo attr = attributes.get(name);
        TypeMirror type = field.asType();

        if (attr == null) {
            attr = new AttributeInfo(name, field.asType(), field, null, null, null);
            AttributeInfo origin = attributes.putIfAbsent(name, attr);
            if (origin != null) {
                attr = origin;
            }
        }

        attr.field = field;
        return attr;
    }

    public AttributeInfo getAttributeByMethod(
            String name,
            TypeMirror type,
            ExecutableElement getter,
            ExecutableElement setter
    ) {<FILL_FUNCTION_BODY>}

    public List<AttributeInfo> getReaderAttributes() {
        return attributes.values()
                .stream()
                .filter(AttributeInfo::supportSet)
                .sorted()
                .collect(Collectors.toList());
    }
}

        AttributeInfo attr = attributes.get(name);
        if (attr == null) {
            attr = new AttributeInfo(name, type, null, getter, setter, null);
            AttributeInfo origin = attributes.putIfAbsent(name, attr);
            if (origin != null) {
                attr = origin;
            }
        }

        if (getter != null) {
            attr.getMethod = getter;
        }
        if (setter != null) {
            attr.setMethod = setter;
        }

        return attr;
    
<no_super_class>