private ClassDefinition createPolymorphicExtensionNodeClass()

in modules/configuration/src/main/java/org/apache/ignite/internal/configuration/asm/InnerNodeAsmGenerator.java [1660:1836]


    private ClassDefinition createPolymorphicExtensionNodeClass(
            Class<?> polymorphicExtension,
            Collection<Field> polymorphicFields
    ) {
        SchemaClassesInfo schemaClassInfo = cgen.schemaInfo(schemaClass);
        SchemaClassesInfo polymorphicExtensionClassInfo = cgen.schemaInfo(polymorphicExtension);

        // Node class definition.
        ClassDefinition classDef = new ClassDefinition(
                EnumSet.of(PUBLIC, FINAL),
                internalName(polymorphicExtensionClassInfo.nodeClassName),
                type(Object.class),
                ArrayUtils.concat(nodeClassInterfaces(polymorphicExtension, Set.of()), type(ConstructableTreeNode.class))
        );

        // private final ParentNode this$0;
        FieldDefinition parentInnerNodeFieldDef = classDef.declareField(
                EnumSet.of(PRIVATE, FINAL),
                "this$0",
                typeFromJavaClassName(schemaClassInfo.nodeClassName)
        );

        // Constructor.
        MethodDefinition constructorMtd = classDef.declareConstructor(
                EnumSet.of(PUBLIC),
                arg("delegate", typeFromJavaClassName(schemaClassInfo.nodeClassName))
        );

        Variable delegateVar = constructorMtd.getScope().getVariable("delegate");

        // Constructor body.
        constructorMtd.getBody()
                .append(constructorMtd.getThis())
                .invokeConstructor(Object.class)
                .append(constructorMtd.getThis().setField(
                        parentInnerNodeFieldDef,
                        delegateVar
                ))
                .ret();

        Map<String, FieldDefinition> fieldDefs = innerNodeClassDef.getFields().stream()
                .collect(toMap(FieldDefinition::getName, identity()));

        // Creates method to get the internal id. Almost the same as regular view, but with method invocation instead of field access.
        if (internalIdField != null) {
            addNodeViewMethod(
                    classDef,
                    internalIdField,
                    viewMtd -> getThisFieldCode(viewMtd, parentInnerNodeFieldDef).invoke(INTERNAL_ID),
                    null
            );
        }

        // Creates view and change methods for parent schema.
        for (Field schemaField : schemaFields) {
            FieldDefinition schemaFieldDef = fieldDefs.get(fieldName(schemaField));

            addNodeViewMethod(
                    classDef,
                    schemaField,
                    viewMtd -> getThisFieldCode(viewMtd, parentInnerNodeFieldDef, schemaFieldDef),
                    null
            );

            // Read only.
            if (isReadOnly(schemaField)) {
                continue;
            }

            List<MethodDefinition> changeMethods = addNodeChangeMethod(
                    classDef,
                    schemaField,
                    changeMtd -> getThisFieldCode(changeMtd, parentInnerNodeFieldDef, schemaFieldDef),
                    (changeMtd, newValue) -> setThisFieldCode(changeMtd, newValue, parentInnerNodeFieldDef, schemaFieldDef),
                    null
            );

            // Only first element requires a bridge. Please refer to "addNodeChangeMethod" for explanation.
            addNodeChangeBridgeMethod(classDef, schemaClassInfo.changeClassName, changeMethods.get(0));
        }

        FieldDefinition polymorphicTypeIdFieldDef = fieldDefs.get(polymorphicIdField(schemaClass).getName());

        // Creates view and change methods for specific polymorphic instance schema.
        for (Field polymorphicField : polymorphicFields) {
            FieldDefinition polymorphicFieldDef = fieldDefs.get(fieldName(polymorphicField));

            addNodeViewMethod(
                    classDef,
                    polymorphicField,
                    viewMtd -> getThisFieldCode(viewMtd, parentInnerNodeFieldDef, polymorphicFieldDef),
                    viewMtd -> getThisFieldCode(viewMtd, parentInnerNodeFieldDef, polymorphicTypeIdFieldDef)
            );

            List<MethodDefinition> changeMethods = addNodeChangeMethod(
                    classDef,
                    polymorphicField,
                    changeMtd -> getThisFieldCode(changeMtd, parentInnerNodeFieldDef, polymorphicFieldDef),
                    (changeMtd, newValue) -> setThisFieldCode(changeMtd, newValue, parentInnerNodeFieldDef, polymorphicFieldDef),
                    changeMtd -> getThisFieldCode(changeMtd, parentInnerNodeFieldDef, polymorphicTypeIdFieldDef)
            );

            // Only first element requires a bridge. Please refer to "addNodeChangeMethod" for explanation.
            addNodeChangeBridgeMethod(classDef, polymorphicExtensionClassInfo.changeClassName, changeMethods.get(0));
        }

        ParameterizedType returnType = typeFromJavaClassName(schemaClassInfo.changeClassName);

        // Creates Node#convert(Class<T> changeClass).
        MethodDefinition convertByChangeClassMtd = classDef.declareMethod(
                EnumSet.of(PUBLIC),
                CONVERT_MTD_NAME,
                returnType,
                arg("changeClass", Class.class)
        );

        // return this.this$0.convert(changeClass);
        convertByChangeClassMtd.getBody()
                .append(getThisFieldCode(convertByChangeClassMtd, parentInnerNodeFieldDef))
                .append(convertByChangeClassMtd.getScope().getVariable("changeClass"))
                .invokeVirtual(innerNodeClassDef.getType(), CONVERT_MTD_NAME, returnType, type(Class.class))
                .retObject();

        // Creates Node#convert(String polymorphicId).
        MethodDefinition convertByPolymorphicTypeIdMtd = classDef.declareMethod(
                EnumSet.of(PUBLIC),
                CONVERT_MTD_NAME,
                returnType,
                arg("polymorphicTypeId", String.class)
        );

        // return this.this$0.convert(polymorphicTypeId);
        convertByPolymorphicTypeIdMtd.getBody()
                .append(getThisFieldCode(convertByPolymorphicTypeIdMtd, parentInnerNodeFieldDef))
                .append(convertByPolymorphicTypeIdMtd.getScope().getVariable("polymorphicTypeId"))
                .invokeVirtual(innerNodeClassDef.getType(), CONVERT_MTD_NAME, returnType, type(String.class))
                .retObject();

        // Creates ConstructableTreeNode#construct.
        MethodDefinition constructMtd = classDef.declareMethod(
                EnumSet.of(PUBLIC),
                CONSTRUCT_MTD_NAME,
                type(void.class),
                arg("key", type(String.class)),
                arg("src", type(ConfigurationSource.class)),
                arg("includeInternal", type(boolean.class))
        ).addException(NoSuchElementException.class);

        // return this.this$0.construct(key, src, includeInternal);
        constructMtd.getBody()
                .append(getThisFieldCode(constructMtd, parentInnerNodeFieldDef))
                .append(constructMtd.getScope().getVariable("key"))
                .append(constructMtd.getScope().getVariable("src"))
                .append(constructMtd.getScope().getVariable("includeInternal"))
                .invokeVirtual(
                        innerNodeClassDef.getType(),
                        CONSTRUCT_MTD_NAME,
                        type(void.class),
                        type(String.class), type(ConfigurationSource.class), type(boolean.class)
                )
                .ret();

        // Creates ConstructableTreeNode#copy.
        MethodDefinition copyMtd = classDef.declareMethod(
                EnumSet.of(PUBLIC),
                "copy",
                type(ConstructableTreeNode.class)
        );

        // return this.this$0.copy();
        copyMtd.getBody()
                .append(getThisFieldCode(copyMtd, parentInnerNodeFieldDef))
                .invokeVirtual(innerNodeClassDef.getType(), "copy", type(ConstructableTreeNode.class))
                .retObject();

        return classDef;
    }