private void createPojoBindings()

in modules/configuration-annotation-processor/src/main/java/org/apache/ignite/internal/configuration/processor/ConfigurationProcessor.java [388:581]


    private void createPojoBindings(
            Collection<VariableElement> fields,
            ClassName schemaClassName,
            TypeSpec.Builder configurationInterfaceBuilder,
            boolean extendBaseSchema,
            TypeElement realSchemaClass,
            boolean isPolymorphicConfig,
            boolean isPolymorphicInstanceConfig
    ) {
        ClassName viewClsName = getViewName(schemaClassName);
        ClassName changeClsName = getChangeName(schemaClassName);

        TypeName configInterfaceType;
        @Nullable TypeName viewBaseSchemaInterfaceType;
        @Nullable TypeName changeBaseSchemaInterfaceType;

        TypeElement superClass = superClass(realSchemaClass);

        boolean isSuperClassAbstractConfiguration = !isClass(superClass.asType(), Object.class)
                && superClass.getAnnotation(AbstractConfiguration.class) != null;

        if (extendBaseSchema || isSuperClassAbstractConfiguration) {
            ClassName superClassSchemaClassName = ClassName.get(superClass);

            viewBaseSchemaInterfaceType = getViewName(superClassSchemaClassName);
            changeBaseSchemaInterfaceType = getChangeName(superClassSchemaClassName);

            if (isSuperClassAbstractConfiguration) {
                // Example: ExtendedTableConfig extends TableConfig<ExtendedTableView, ExtendedTableChange>
                configInterfaceType = ParameterizedTypeName.get(
                        getConfigurationInterfaceName(superClassSchemaClassName),
                        viewClsName,
                        changeClsName
                );
            } else {
                // Example: ExtendedTableConfig extends TableConfig
                configInterfaceType = getConfigurationInterfaceName(superClassSchemaClassName);
            }
        } else {
            ClassName confTreeInterface = ClassName.get("org.apache.ignite.configuration", "ConfigurationTree");

            if (realSchemaClass.getAnnotation(AbstractConfiguration.class) != null) {
                // Example: TableConfig<VIEWT extends TableView, CHANGET extends TableChange> extends ConfigurationTree<VIEWT, CHANGET>
                configurationInterfaceBuilder.addTypeVariables(List.of(
                        TypeVariableName.get("VIEWT", viewClsName),
                        TypeVariableName.get("CHANGET", changeClsName)
                ));

                configInterfaceType = ParameterizedTypeName.get(
                        confTreeInterface,
                        TypeVariableName.get("VIEWT"),
                        TypeVariableName.get("CHANGET")
                );
            } else {
                // Example: TableConfig extends ConfigurationTree<TableView, TableChange>
                configInterfaceType = ParameterizedTypeName.get(confTreeInterface, viewClsName, changeClsName);
            }

            viewBaseSchemaInterfaceType = null;
            changeBaseSchemaInterfaceType = null;
        }

        configurationInterfaceBuilder.addSuperinterface(configInterfaceType);

        // This code will be refactored in the future. Right now I don't want to entangle it with existing code
        // generation. It has only a few considerable problems - hardcode and a lack of proper arrays handling.
        // Clone method should be used to guarantee data integrity.

        TypeSpec.Builder viewClsBuilder = TypeSpec.interfaceBuilder(viewClsName)
                .addModifiers(PUBLIC);

        if (viewBaseSchemaInterfaceType != null) {
            viewClsBuilder.addSuperinterface(viewBaseSchemaInterfaceType);
        }

        TypeSpec.Builder changeClsBuilder = TypeSpec.interfaceBuilder(changeClsName)
                .addSuperinterface(viewClsName)
                .addModifiers(PUBLIC);

        if (changeBaseSchemaInterfaceType != null) {
            changeClsBuilder.addSuperinterface(changeBaseSchemaInterfaceType);
        }

        if (isPolymorphicInstanceConfig) {
            changeClsBuilder.addSuperinterface(POLYMORPHIC_CHANGE_CLASSNAME);
        }

        ClassName consumerClsName = ClassName.get(Consumer.class);

        for (VariableElement field : fields) {
            Value valAnnotation = field.getAnnotation(Value.class);

            String fieldName = field.getSimpleName().toString();
            TypeMirror schemaFieldType = field.asType();
            TypeName schemaFieldTypeName = TypeName.get(schemaFieldType);

            boolean leafField = isValidValueAnnotationFieldType(schemaFieldType)
                    || !((ClassName) schemaFieldTypeName).simpleName().contains(CONFIGURATION_SCHEMA_POSTFIX);

            boolean namedListField = field.getAnnotation(NamedConfigValue.class) != null;

            TypeName viewFieldType =
                    leafField ? schemaFieldTypeName : getViewName((ClassName) schemaFieldTypeName);

            TypeName changeFieldType =
                    leafField ? schemaFieldTypeName : getChangeName((ClassName) schemaFieldTypeName);

            if (namedListField) {
                changeFieldType = ParameterizedTypeName.get(
                        ClassName.get(NamedListChange.class),
                        viewFieldType,
                        changeFieldType
                );

                viewFieldType = ParameterizedTypeName.get(
                        ClassName.get(NamedListView.class),
                        WildcardTypeName.subtypeOf(viewFieldType)
                );
            }

            MethodSpec.Builder getMtdBuilder = MethodSpec.methodBuilder(fieldName)
                    .addModifiers(PUBLIC, ABSTRACT)
                    .returns(viewFieldType);

            viewClsBuilder.addMethod(getMtdBuilder.build());

            // Read only.
            if (field.getAnnotation(PolymorphicId.class) != null || field.getAnnotation(InjectedName.class) != null
                    || field.getAnnotation(InternalId.class) != null) {
                continue;
            }

            String changeMtdName = "change" + capitalize(fieldName);

            MethodSpec.Builder changeMtdBuilder = MethodSpec.methodBuilder(changeMtdName)
                    .addModifiers(PUBLIC, ABSTRACT)
                    .returns(changeClsName);

            if (valAnnotation != null) {
                if (schemaFieldType.getKind() == TypeKind.ARRAY) {
                    changeMtdBuilder.varargs(true);
                }

                changeMtdBuilder.addParameter(changeFieldType, fieldName);
            } else {
                changeMtdBuilder.addParameter(ParameterizedTypeName.get(consumerClsName, changeFieldType), fieldName);
            }

            changeClsBuilder.addMethod(changeMtdBuilder.build());

            // Create "FooChange changeFoo()" method with no parameters, if it's a config value or named list value.
            if (valAnnotation == null) {
                MethodSpec.Builder shortChangeMtdBuilder = MethodSpec.methodBuilder(changeMtdName)
                        .addModifiers(PUBLIC, ABSTRACT)
                        .returns(changeFieldType);

                changeClsBuilder.addMethod(shortChangeMtdBuilder.build());
            }
        }

        if (isPolymorphicConfig) {
            // Parameter type: Class<T>.
            ParameterizedTypeName parameterType = ParameterizedTypeName.get(
                    ClassName.get(Class.class),
                    TypeVariableName.get("T")
            );

            // Variable type, for example: <T extends SimpleChange & PolymorphicChange>.
            TypeVariableName typeVariable = TypeVariableName.get("T", changeClsName, POLYMORPHIC_CHANGE_CLASSNAME);

            // Method like: <T extends SimpleChange & PolymorphicChange> T convert(Class<T> changeClass);
            MethodSpec.Builder convertByChangeClassMtdBuilder = MethodSpec.methodBuilder("convert")
                    .addModifiers(PUBLIC, ABSTRACT)
                    .addTypeVariable(typeVariable)
                    .addParameter(parameterType, "changeClass")
                    .returns(TypeVariableName.get("T"));

            changeClsBuilder.addMethod(convertByChangeClassMtdBuilder.build());

            // Method like: SimpleChange convert(String polymorphicTypeId);
            MethodSpec.Builder convertByStringMtdBuilder = MethodSpec.methodBuilder("convert")
                    .addModifiers(PUBLIC, ABSTRACT)
                    .addParameter(ClassName.get(String.class), "polymorphicTypeId")
                    .returns(changeClsName);

            changeClsBuilder.addMethod(convertByStringMtdBuilder.build());
        }

        TypeSpec viewCls = viewClsBuilder.build();
        TypeSpec changeCls = changeClsBuilder.build();

        buildClass(viewClsName.packageName(), viewCls);
        buildClass(changeClsName.packageName(), changeCls);
    }