You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@ignite.apache.org by GitBox <gi...@apache.org> on 2022/12/13 13:57:28 UTC

[GitHub] [ignite-3] rpuch commented on a diff in pull request #1431: IGNITE-17167 ConfigurationAsmGenerator decomposition

rpuch commented on code in PR #1431:
URL: https://github.com/apache/ignite-3/pull/1431#discussion_r1046991968


##########
modules/configuration/src/main/java/org/apache/ignite/internal/configuration/asm/AbstractAsmGenerator.java:
##########
@@ -0,0 +1,285 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.configuration.asm;
+
+import com.facebook.presto.bytecode.ClassDefinition;
+import java.io.Serializable;
+import java.lang.invoke.LambdaMetafactory;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles.Lookup;
+import java.lang.invoke.MethodType;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.Consumer;
+import org.apache.ignite.configuration.ConfigurationProperty;
+import org.apache.ignite.configuration.RootKey;
+import org.apache.ignite.internal.configuration.ConfigurationNode;
+import org.apache.ignite.internal.configuration.DynamicConfiguration;
+import org.apache.ignite.internal.configuration.DynamicConfigurationChanger;
+import org.apache.ignite.internal.configuration.direct.DirectConfigurationProxy;
+import org.apache.ignite.internal.configuration.tree.ConfigurationSource;
+import org.apache.ignite.internal.configuration.tree.ConfigurationVisitor;
+import org.apache.ignite.internal.configuration.tree.ConstructableTreeNode;
+import org.apache.ignite.internal.configuration.tree.InnerNode;
+import org.apache.ignite.internal.configuration.tree.NamedListNode;
+import org.apache.ignite.internal.configuration.util.ConfigurationUtil;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Class that holds constants and commonly used fields for generators.
+ */
+abstract class AbstractAsmGenerator {
+    /** {@link DynamicConfiguration#DynamicConfiguration} constructor. */
+    static final Constructor<?> DYNAMIC_CONFIGURATION_CTOR;
+
+    /** {@link LambdaMetafactory#metafactory(Lookup, String, MethodType, MethodType, MethodHandle, MethodType)}. */
+    static final Method LAMBDA_METAFACTORY;
+
+    /** {@link Consumer#accept(Object)}. */
+    static final Method ACCEPT;
+
+    /** {@link ConfigurationVisitor#visitLeafNode(String, Serializable)}. */
+    static final Method VISIT_LEAF;
+
+    /** {@link ConfigurationVisitor#visitInnerNode(String, InnerNode)}. */
+    static final Method VISIT_INNER;
+
+    /** {@link ConfigurationVisitor#visitNamedListNode(String, NamedListNode)}. */
+    static final Method VISIT_NAMED;
+
+    /** {@link ConfigurationSource#unwrap(Class)}. */
+    static final Method UNWRAP;
+
+    /** {@link ConfigurationSource#descend(ConstructableTreeNode)}. */
+    static final Method DESCEND;
+
+    /** {@link ConstructableTreeNode#copy()}. */
+    static final Method COPY;
+
+    /** {@link InnerNode#internalId()}. */
+    static final Method INTERNAL_ID;
+
+    /** {@code DynamicConfiguration#add} method. */
+    static final Method DYNAMIC_CONFIGURATION_ADD_MTD;
+
+    /** {@link Objects#requireNonNull(Object, String)}. */
+    static final Method REQUIRE_NON_NULL;
+
+    /** {@link Class#getName} method. */
+    static final Method CLASS_GET_NAME_MTD;
+
+    /** {@link String#equals} method. */
+    static final Method STRING_EQUALS_MTD;
+
+    /** {@link ConfigurationSource#polymorphicTypeId} method. */
+    static final Method POLYMORPHIC_TYPE_ID_MTD;
+
+    /** {@link InnerNode#constructDefault} method. */
+    static final Method CONSTRUCT_DEFAULT_MTD;
+
+    /** {@code ConfigurationNode#refreshValue} method. */
+    static final Method REFRESH_VALUE_MTD;
+
+    /** {@code DynamicConfiguration#addMember} method. */
+    static final Method ADD_MEMBER_MTD;
+
+    /** {@code DynamicConfiguration#removeMember} method. */
+    static final Method REMOVE_MEMBER_MTD;
+
+    /** {@link InnerNode#specificNode} method. */
+    static final Method SPECIFIC_NODE_MTD;
+
+    /** {@link DynamicConfiguration#specificConfigTree} method. */
+    static final Method SPECIFIC_CONFIG_TREE_MTD;
+
+    /** {@link ConfigurationUtil#addDefaults}. */
+    static final Method ADD_DEFAULTS_MTD;
+
+    /** {@link InnerNode#setInjectedNameFieldValue}. */
+    static final Method SET_INJECTED_NAME_FIELD_VALUE_MTD;
+
+    /** {@code ConfigurationNode#currentValue}. */
+    static final Method CURRENT_VALUE_MTD;
+
+    /** {@link DynamicConfiguration#isRemovedFromNamedList}. */
+    static final Method IS_REMOVED_FROM_NAMED_LIST_MTD;
+
+    /** {@link InnerNode#isPolymorphic}. */
+    static final Method IS_POLYMORPHIC_MTD;
+
+    /** {@link InnerNode#internalSchemaTypes}. */
+    static final Method INTERNAL_SCHEMA_TYPES_MTD;
+
+    /** {@code Node#convert} method name. */
+    static final String CONVERT_MTD_NAME = "convert";
+
+    /** {@link ConstructableTreeNode#construct(String, ConfigurationSource, boolean)} method name. */
+    static final String CONSTRUCT_MTD_NAME = "construct";
+
+    /** Field name for method {@link DynamicConfiguration#internalConfigTypes}. */
+    static final String INTERNAL_CONFIG_TYPES_FIELD_NAME = "_internalConfigTypes";
+
+    /** {@link DirectConfigurationProxy#DirectConfigurationProxy(List, DynamicConfigurationChanger)}. */
+    static final Constructor<?> DIRECT_CFG_CTOR;
+
+    /** {@link ConfigurationUtil#appendKey(List, Object)}. */
+    static final Method APPEND_KEY;
+
+    static {
+        try {
+            LAMBDA_METAFACTORY = LambdaMetafactory.class.getDeclaredMethod(
+                    "metafactory",
+                    Lookup.class,
+                    String.class,
+                    MethodType.class,
+                    MethodType.class,
+                    MethodHandle.class,
+                    MethodType.class
+            );
+
+            ACCEPT = Consumer.class.getDeclaredMethod("accept", Object.class);
+
+            VISIT_LEAF = ConfigurationVisitor.class
+                    .getDeclaredMethod("visitLeafNode", String.class, Serializable.class);
+
+            VISIT_INNER = ConfigurationVisitor.class
+                    .getDeclaredMethod("visitInnerNode", String.class, InnerNode.class);
+
+            VISIT_NAMED = ConfigurationVisitor.class
+                    .getDeclaredMethod("visitNamedListNode", String.class, NamedListNode.class);
+
+            UNWRAP = ConfigurationSource.class.getDeclaredMethod("unwrap", Class.class);
+
+            DESCEND = ConfigurationSource.class.getDeclaredMethod("descend", ConstructableTreeNode.class);
+
+            COPY = ConstructableTreeNode.class.getDeclaredMethod("copy");
+
+            INTERNAL_ID = InnerNode.class.getDeclaredMethod("internalId");
+
+            DYNAMIC_CONFIGURATION_CTOR = DynamicConfiguration.class.getDeclaredConstructor(
+                    List.class,
+                    String.class,
+                    RootKey.class,
+                    DynamicConfigurationChanger.class,
+                    boolean.class
+            );
+
+            DYNAMIC_CONFIGURATION_ADD_MTD = DynamicConfiguration.class.getDeclaredMethod(
+                    "add",
+                    ConfigurationProperty.class
+            );
+
+            REQUIRE_NON_NULL = Objects.class.getDeclaredMethod("requireNonNull", Object.class, String.class);
+
+            CLASS_GET_NAME_MTD = Class.class.getDeclaredMethod("getName");
+
+            STRING_EQUALS_MTD = String.class.getDeclaredMethod("equals", Object.class);
+
+            POLYMORPHIC_TYPE_ID_MTD = ConfigurationSource.class.getDeclaredMethod("polymorphicTypeId", String.class);
+
+            CONSTRUCT_DEFAULT_MTD = InnerNode.class.getDeclaredMethod("constructDefault", String.class);
+
+            REFRESH_VALUE_MTD = ConfigurationNode.class.getDeclaredMethod("refreshValue");
+
+            ADD_MEMBER_MTD = DynamicConfiguration.class.getDeclaredMethod("addMember", Map.class, ConfigurationProperty.class);
+
+            REMOVE_MEMBER_MTD = DynamicConfiguration.class.getDeclaredMethod("removeMember", Map.class, ConfigurationProperty.class);
+
+            SPECIFIC_NODE_MTD = InnerNode.class.getDeclaredMethod("specificNode");
+
+            SPECIFIC_CONFIG_TREE_MTD = DynamicConfiguration.class.getDeclaredMethod("specificConfigTree");
+
+            ADD_DEFAULTS_MTD = ConfigurationUtil.class.getDeclaredMethod("addDefaults", InnerNode.class);
+
+            SET_INJECTED_NAME_FIELD_VALUE_MTD = InnerNode.class.getDeclaredMethod("setInjectedNameFieldValue", String.class);
+
+            CURRENT_VALUE_MTD = ConfigurationNode.class.getDeclaredMethod("currentValue");
+
+            IS_REMOVED_FROM_NAMED_LIST_MTD = DynamicConfiguration.class.getDeclaredMethod("isRemovedFromNamedList");
+
+            IS_POLYMORPHIC_MTD = InnerNode.class.getDeclaredMethod("isPolymorphic");
+
+            INTERNAL_SCHEMA_TYPES_MTD = InnerNode.class.getDeclaredMethod("internalSchemaTypes");
+
+            DIRECT_CFG_CTOR = DirectConfigurationProxy.class.getDeclaredConstructor(List.class, DynamicConfigurationChanger.class);
+
+            APPEND_KEY = ConfigurationUtil.class.getDeclaredMethod("appendKey", List.class, Object.class);
+        } catch (NoSuchMethodException nsme) {
+            throw new ExceptionInInitializerError(nsme);
+        }
+    }
+
+    /** This generator instance. */
+    final ConfigurationAsmGenerator cgen;
+
+    /** Configuration schema class. */
+    final Class<?> schemaClass;
+
+    /** Internal extensions of the configuration schema. */
+    final Set<Class<?>> internalExtensions;
+
+    /** Polymorphic extensions of the configuration schema. */
+    final Set<Class<?>> polymorphicExtensions;
+
+    /** Fields of the schema class. */
+    final List<Field> schemaFields;
+
+    /** Fields of internal extensions of the configuration schema. */
+    final Collection<Field> internalFields;
+
+    /** Fields of polymorphic extensions of the configuration schema. */
+    final Collection<Field> polymorphicFields;
+
+    /** Internal id field or {@code null} if it's not present. */
+    final Field internalIdField;
+
+    /**
+     * Constructor.
+     * Please refer to individual fields for comments.
+     */
+    AbstractAsmGenerator(
+            ConfigurationAsmGenerator cgen,
+            Class<?> schemaClass,
+            Set<Class<?>> internalExtensions,
+            Set<Class<?>> polymorphicExtensions,
+            List<Field> schemaFields,
+            Collection<Field> internalFields,
+            Collection<Field> polymorphicFields,
+            @Nullable Field internalIdField
+    ) {
+        this.cgen = cgen;
+        this.schemaClass = schemaClass;
+        this.internalExtensions = internalExtensions;
+        this.polymorphicExtensions = polymorphicExtensions;
+        this.schemaFields = schemaFields;
+        this.internalFields = internalFields;
+        this.polymorphicFields = polymorphicFields;
+        this.internalIdField = internalIdField;
+    }
+
+    /**
+     * Generates class definition. Expected to be called once at most.

Review Comment:
   It's not just one definition, it's definitionS.
   
   Don't we also need an explanation of why more than one definition might be generated?



##########
modules/configuration/src/main/java/org/apache/ignite/internal/configuration/asm/ConfigurationAsmGenerator.java:
##########
@@ -570,1669 +312,116 @@ private Field internalIdField(Class<?> schemaClass, Set<Class<?>> schemaExtensio
     }
 
     /**
-     * Construct a {@link InnerNode} definition for a configuration schema.
+     * Copies field into itself or instantiates it if the field is null. Code like: {@code this.field == null ? new ValueNode() :
+     * (ValueNode)this.field.copy();}.
      *
-     * @param schemaClass           Configuration schema class.
-     * @param internalExtensions    Internal extensions of the configuration schema.
-     * @param polymorphicExtensions Polymorphic extensions of the configuration schema.
-     * @param schemaFields          Fields of the schema class.
-     * @param internalFields        Fields of internal extensions of the configuration schema.
-     * @param polymorphicFields     Fields of polymorphic extensions of the configuration schema.
-     * @param internalIdField       Internal id field or {@code null} if it's not present.
-     * @return Constructed {@link InnerNode} definition for the configuration schema.
+     * @param schemaField  Configuration schema class field.
+     * @param getFieldCode Bytecode of getting the field, for example: {@code this.field} or {@code this.field.field};
+     * @return Bytecode expression.
      */
-    private ClassDefinition createNodeClass(
-            Class<?> schemaClass,
-            Set<Class<?>> internalExtensions,
-            Set<Class<?>> polymorphicExtensions,
-            List<Field> schemaFields,
-            Collection<Field> internalFields,
-            Collection<Field> polymorphicFields,
-            @Nullable Field internalIdField
-    ) {
-        SchemaClassesInfo schemaClassInfo = schemasInfo.get(schemaClass);
-
-        // Node class definition.
-        ClassDefinition classDef = new ClassDefinition(
-                of(PUBLIC, FINAL),
-                internalName(schemaClassInfo.nodeClassName),
-                type(InnerNode.class),
-                nodeClassInterfaces(schemaClass, internalExtensions)
-        );
-
-        // Spec fields.
-        Map<Class<?>, FieldDefinition> specFields = new HashMap<>();
-
-        int i = 0;
-
-        for (Class<?> clazz : concat(List.of(schemaClass), internalExtensions, polymorphicExtensions)) {
-            specFields.put(clazz, classDef.declareField(of(PRIVATE, FINAL), "_spec" + i++, clazz));
-        }
-
-        // Define the rest of the fields.
-        Map<String, FieldDefinition> fieldDefs = new HashMap<>();
-
-        // To store the id of the polymorphic configuration instance.
-        FieldDefinition polymorphicTypeIdFieldDef = null;
-
-        // Field with @InjectedName.
-        FieldDefinition injectedNameFieldDef = null;
-
-        for (Field schemaField : concat(schemaFields, internalFields, polymorphicFields)) {
-            String fieldName = fieldName(schemaField);
-
-            FieldDefinition fieldDef = addNodeField(classDef, schemaField, fieldName);
-
-            fieldDefs.put(fieldName, fieldDef);
-
-            if (isPolymorphicId(schemaField)) {
-                polymorphicTypeIdFieldDef = fieldDef;
-            } else if (isInjectedName(schemaField)) {
-                injectedNameFieldDef = fieldDef;
-            }
-        }
-
-        // org.apache.ignite.internal.configuration.tree.InnerNode#schemaType
-        addNodeSchemaTypeMethod(classDef, schemaClass, polymorphicExtensions, polymorphicTypeIdFieldDef);
-
-        FieldDefinition internalSchemaTypesFieldDef = null;
-
-        if (!internalExtensions.isEmpty()) {
-            internalSchemaTypesFieldDef = classDef.declareField(
-                    of(PRIVATE, FINAL),
-                    "_" + INTERNAL_SCHEMA_TYPES_MTD.getName(),
-                    Class[].class
-            );
-        }
-
-        // Constructor.
-        addNodeConstructor(
-                classDef,
-                specFields,
-                fieldDefs,
-                schemaFields,
-                internalFields,
-                polymorphicFields,
-                internalExtensions,
-                internalSchemaTypesFieldDef
-        );
-
-        // Add view method for internal id.
-        if (internalIdField != null) {
-            addNodeInternalIdMethod(classDef, internalIdField);
-        }
-
-        // VIEW and CHANGE methods.
-        for (Field schemaField : concat(schemaFields, internalFields)) {
-            String fieldName = schemaField.getName();
-
-            FieldDefinition fieldDef = fieldDefs.get(fieldName);
-
-            addNodeViewMethod(
-                    classDef,
-                    schemaField,
-                    viewMtd -> getThisFieldCode(viewMtd, fieldDef),
-                    null
-            );
-
-            // Read only.
-            if (isPolymorphicId(schemaField) || isInjectedName(schemaField)) {
-                continue;
-            }
-
-            // Add change methods.
-            MethodDefinition changeMtd0 = addNodeChangeMethod(
-                    classDef,
-                    schemaField,
-                    changeMtd -> getThisFieldCode(changeMtd, fieldDef),
-                    (changeMtd, newValue) -> setThisFieldCode(changeMtd, newValue, fieldDef),
-                    null
-            );
-
-            addNodeChangeBridgeMethod(classDef, changeClassName(schemaField.getDeclaringClass()), changeMtd0);
-        }
-
-        Map<Class<?>, List<Field>> polymorphicFieldsByExtension = Map.of();
-
-        MethodDefinition changePolymorphicTypeIdMtd = null;
-
-        if (!polymorphicExtensions.isEmpty()) {
-            assert polymorphicTypeIdFieldDef != null : schemaClass.getName();
-
-            addNodeSpecificNodeMethod(classDef, polymorphicExtensions, polymorphicTypeIdFieldDef);
-
-            changePolymorphicTypeIdMtd = addNodeChangePolymorphicTypeIdMethod(
-                    classDef,
-                    fieldDefs,
-                    polymorphicExtensions,
-                    polymorphicFields,
-                    polymorphicTypeIdFieldDef
-            );
-
-            addNodeConvertMethods(classDef, schemaClass, polymorphicExtensions, changePolymorphicTypeIdMtd);
-
-            polymorphicFieldsByExtension = new LinkedHashMap<>();
-
-            for (Class<?> polymorphicExtension : polymorphicExtensions) {
-                polymorphicFieldsByExtension.put(
-                        polymorphicExtension,
-                        polymorphicFields.stream()
-                                .filter(f -> polymorphicExtension.equals(f.getDeclaringClass()))
-                                .collect(toList())
-                );
-            }
-        }
-
-        // traverseChildren
-        addNodeTraverseChildrenMethod(
-                classDef,
-                schemaClass,
-                fieldDefs,
-                schemaFields,
-                internalFields,
-                polymorphicFieldsByExtension,
-                polymorphicTypeIdFieldDef
-        );
-
-        // traverseChild
-        addNodeTraverseChildMethod(
-                classDef,
-                fieldDefs,
-                schemaFields,
-                internalFields,
-                polymorphicFieldsByExtension,
-                polymorphicTypeIdFieldDef
-        );
-
-        // construct
-        addNodeConstructMethod(
-                classDef,
-                fieldDefs,
-                schemaFields,
-                internalFields,
-                polymorphicFieldsByExtension,
-                polymorphicTypeIdFieldDef,
-                changePolymorphicTypeIdMtd
-        );
+    BytecodeExpression newOrCopyNodeField(Field schemaField, BytecodeExpression getFieldCode) {
+        ParameterizedType nodeType = typeFromJavaClassName(schemasInfo.get(schemaField.getType()).nodeClassName);
 
-        // constructDefault
-        addNodeConstructDefaultMethod(
-                schemaClass,
-                classDef,
-                specFields,
-                fieldDefs,
-                schemaFields,
-                internalFields,
-                polymorphicFieldsByExtension,
-                polymorphicTypeIdFieldDef
+        // this.field == null ? new ValueNode() : (ValueNode)this.field.copy();
+        return inlineIf(
+                isNull(getFieldCode),
+                newInstance(nodeType),
+                copyNodeField(schemaField, getFieldCode)
         );
+    }
 
-        if (injectedNameFieldDef != null) {
-            addInjectedNameFieldMethods(classDef, injectedNameFieldDef);
-        }
-
-        if (polymorphicTypeIdFieldDef != null) {
-            addIsPolymorphicMethod(classDef);
-        }
-
-        if (internalSchemaTypesFieldDef != null) {
-            addInternalSchemaTypesMethod(classDef, internalSchemaTypesFieldDef);
-        }
-
-        if (schemaClass.getSuperclass().isAnnotationPresent(AbstractConfiguration.class)) {
-            addIsExtendAbstractConfigurationMethod(classDef);
-        }
+    /**
+     * Copies field into itself. Code like: {@code (ValueNode)this.field.copy();}.
+     *
+     * @param schemaField  Configuration schema class field.
+     * @param getFieldCode Bytecode of getting the field, for example: {@code this.field} or {@code this.field.field};
+     * @return Bytecode expression.
+     */
+    BytecodeExpression copyNodeField(Field schemaField, BytecodeExpression getFieldCode) {
+        ParameterizedType nodeType = isNamedConfigValue(schemaField)
+                ? type(NamedListNode.class) : typeFromJavaClassName(schemasInfo.get(schemaField.getType()).nodeClassName);
 
-        return classDef;
+        // (ValueNode)this.field.copy();
+        return getFieldCode.invoke(COPY).cast(nodeType);
     }
 
     /**
-     * Add {@link InnerNode#schemaType} method implementation to the class.
+     * Creates {@code *Node::new} lambda expression with {@link Supplier} type.
      *
-     * @param classDef                  Class definition.
-     * @param schemaClass               Configuration schema class.
-     * @param polymorphicExtensions     Polymorphic extensions of the configuration schema.
-     * @param polymorphicTypeIdFieldDef Identification field for the polymorphic configuration instance.
+     * @param nodeClassName Name of the {@code *Node} class.
+     * @return InvokeDynamic bytecode expression.
      */
-    private static void addNodeSchemaTypeMethod(
-            ClassDefinition classDef,
-            Class<?> schemaClass,
-            Set<Class<?>> polymorphicExtensions,
-            @Nullable FieldDefinition polymorphicTypeIdFieldDef
-    ) {
-        MethodDefinition schemaTypeMtd = classDef.declareMethod(
-                of(PUBLIC),
-                "schemaType",
-                type(Class.class)
+    @NotNull
+    private static BytecodeExpression newNamedListElementLambda(String nodeClassName) {
+        return invokeDynamic(
+                LAMBDA_METAFACTORY,
+                asList(
+                        getMethodType(getType(Object.class)),
+                        new Handle(
+                                H_NEWINVOKESPECIAL,
+                                internalName(nodeClassName),
+                                "<init>",
+                                getMethodDescriptor(Type.VOID_TYPE),
+                                false
+                        ),
+                        getMethodType(typeFromJavaClassName(nodeClassName).getAsmType())
+                ),
+                "get",
+                methodType(Supplier.class)
         );
-
-        BytecodeBlock mtdBody = schemaTypeMtd.getBody();
-
-        if (polymorphicExtensions.isEmpty()) {
-            mtdBody.append(constantClass(schemaClass)).retObject();
-        } else {
-            assert polymorphicTypeIdFieldDef != null : classDef.getName();
-
-            StringSwitchBuilder switchBuilderTypeId = typeIdSwitchBuilder(schemaTypeMtd, polymorphicTypeIdFieldDef);
-
-            for (Class<?> polymorphicExtension : polymorphicExtensions) {
-                switchBuilderTypeId.addCase(
-                        polymorphicInstanceId(polymorphicExtension),
-                        constantClass(polymorphicExtension).ret()
-                );
-            }
-
-            mtdBody.append(switchBuilderTypeId.build());
-        }
     }
 
     /**
-     * Declares field that corresponds to configuration value. Depending on the schema, 5 options possible:
-     * <ul>
-     *     <li>
-     *         {@code @Value public type fieldName}<br/>becomes<br/>
-     *         {@code public BoxedType fieldName}
-     *     </li>
-     *     <li>
-     *         {@code @ConfigValue public MyConfigurationSchema fieldName}<br/>becomes<br/>
-     *         {@code public MyNode fieldName}
-     *     </li>
-     *     <li>
-     *         {@code @NamedConfigValue public type fieldName}<br/>becomes<br/>
-     *         {@code public NamedListNode fieldName}
-     *     </li>
-     *     <li>
-     *         {@code @PolymorphicId public String fieldName}<br/>becomes<br/>
-     *         {@code public String fieldName}
-     *     </li>
-     *     <li>
-     *         {@code @InjectedName public String fieldName}<br/>becomes<br/>
-     *         {@code public String fieldName}
-     *     </li>
-     * </ul>
+     * Replaces first letter in string with its upper-cased variant.
      *
-     * @param classDef    Node class definition.
-     * @param schemaField Configuration Schema class field.
-     * @param fieldName   Field name.
-     * @return Declared field definition.
-     * @throws IllegalArgumentException If an unsupported {@code schemaField} was passed.
+     * @param name Some string.
+     * @return Capitalized version of passed string.
      */
-    private FieldDefinition addNodeField(ClassDefinition classDef, Field schemaField, String fieldName) {
-        Class<?> schemaFieldClass = schemaField.getType();
-
-        ParameterizedType nodeFieldType;
-
-        if (isValue(schemaField) || isPolymorphicId(schemaField) || isInjectedName(schemaField)) {
-            nodeFieldType = type(box(schemaFieldClass));
-        } else if (isConfigValue(schemaField)) {
-            nodeFieldType = typeFromJavaClassName(schemasInfo.get(schemaFieldClass).nodeClassName);
-        } else if (isNamedConfigValue(schemaField)) {
-            nodeFieldType = type(NamedListNode.class);
-        } else {
-            throw new IllegalArgumentException("Unsupported field: " + schemaField);
-        }
-
-        return classDef.declareField(of(PUBLIC), fieldName, nodeFieldType);
+    private static String capitalize(String name) {
+        return name.substring(0, 1).toUpperCase() + name.substring(1);
     }
 
     /**
-     * Implements default constructor for the node class. It initializes {@code _spec} field and every other field that represents named
-     * list configuration.
+     * Returns internalized version of class name, replacing dots with slashes.
      *
-     * @param classDef Node class definition.
-     * @param specFields Definition of fields for the {@code _spec#} fields of the node class. Mapping: configuration schema class -> {@code
-     * _spec#} field.
-     * @param fieldDefs Field definitions for all fields of node class excluding {@code _spec}.
-     * @param schemaFields Fields of the schema class.
-     * @param internalFields Fields of internal extensions of the configuration schema.
-     * @param polymorphicFields Fields of polymorphic extensions of the configuration schema.
-     * @param internalExtensions Internal extensions of the configuration schema.
-     * @param internalSchemaTypesFieldDef Final field which stores {@code internalExtensions}.
+     * @param className Class name (with package).
+     * @return Internal class name.
+     * @see Type#getInternalName(Class)
      */
-    private void addNodeConstructor(
-            ClassDefinition classDef,
-            Map<Class<?>, FieldDefinition> specFields,
-            Map<String, FieldDefinition> fieldDefs,
-            Collection<Field> schemaFields,
-            Collection<Field> internalFields,
-            Collection<Field> polymorphicFields,
-            Set<Class<?>> internalExtensions,
-            @Nullable FieldDefinition internalSchemaTypesFieldDef
-    ) {
-        MethodDefinition ctor = classDef.declareConstructor(of(PUBLIC));
-
-        BytecodeBlock ctorBody = ctor.getBody();
-
-        // super();
-        ctorBody
-                .append(ctor.getThis())
-                .invokeConstructor(InnerNode.class);
-
-        // this._spec# = new MyConfigurationSchema();
-        for (Map.Entry<Class<?>, FieldDefinition> e : specFields.entrySet()) {
-            ctorBody.append(ctor.getThis().setField(e.getValue(), newInstance(e.getKey())));
-        }
-
-        for (Field schemaField : concat(schemaFields, internalFields, polymorphicFields)) {
-            if (!isNamedConfigValue(schemaField)) {
-                continue;
-            }
-
-            FieldDefinition fieldDef = fieldDefs.get(fieldName(schemaField));
-
-            // this.values = new NamedListNode<>(key, ValueNode::new, "polymorphicIdFieldName");
-            ctorBody.append(setThisFieldCode(ctor, newNamedListNode(schemaField), fieldDef));
-        }
-
-        if (!internalExtensions.isEmpty()) {
-            assert internalSchemaTypesFieldDef != null : classDef;
-
-            // Class[] tmp;
-            Variable tmpVar = ctor.getScope().createTempVariable(Class[].class);
-
-            BytecodeBlock initInternalSchemaTypesField = new BytecodeBlock();
-
-            // tmp = new Class[size];
-            initInternalSchemaTypesField.append(tmpVar.set(newArray(type(Class[].class), internalExtensions.size())));
-
-            int i = 0;
-
-            for (Class<?> extension : internalExtensions) {
-                // tmp[i] = InternalTableConfigurationSchema.class;
-                initInternalSchemaTypesField.append(set(
-                        tmpVar,
-                        constantInt(i++),
-                        constantClass(extension)
-                ));
-            }
-
-            // this._internalConfigTypes = tmp;
-            initInternalSchemaTypesField.append(setThisFieldCode(ctor, tmpVar, internalSchemaTypesFieldDef));
-
-            ctorBody.append(initInternalSchemaTypesField);
-        }
-
-        // return;
-        ctorBody.ret();
+    @NotNull

Review Comment:
   We have a convention of not using `@NotNull` annotation



##########
modules/configuration/src/main/java/org/apache/ignite/internal/configuration/asm/ConfigurationImplAsmGenerator.java:
##########
@@ -0,0 +1,872 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.configuration.asm;
+
+import static com.facebook.presto.bytecode.Access.FINAL;
+import static com.facebook.presto.bytecode.Access.PRIVATE;
+import static com.facebook.presto.bytecode.Access.PUBLIC;
+import static com.facebook.presto.bytecode.Access.STATIC;
+import static com.facebook.presto.bytecode.Access.SYNTHETIC;
+import static com.facebook.presto.bytecode.Parameter.arg;
+import static com.facebook.presto.bytecode.ParameterizedType.type;
+import static com.facebook.presto.bytecode.ParameterizedType.typeFromJavaClassName;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.constantBoolean;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.constantClass;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.constantInt;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.constantString;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.inlineIf;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.invokeDynamic;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.newArray;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.newInstance;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.set;
+import static java.util.Arrays.asList;
+import static java.util.Collections.emptyList;
+import static java.util.EnumSet.of;
+import static java.util.function.Function.identity;
+import static java.util.stream.Collectors.toList;
+import static java.util.stream.Collectors.toMap;
+import static org.apache.ignite.internal.configuration.asm.ConfigurationAsmGenerator.fieldName;
+import static org.apache.ignite.internal.configuration.asm.ConfigurationAsmGenerator.getThisFieldCode;
+import static org.apache.ignite.internal.configuration.asm.ConfigurationAsmGenerator.internalName;
+import static org.apache.ignite.internal.configuration.asm.ConfigurationAsmGenerator.setThisFieldCode;
+import static org.apache.ignite.internal.configuration.asm.ConfigurationAsmGenerator.throwException;
+import static org.apache.ignite.internal.configuration.asm.DirectProxyAsmGenerator.newDirectProxyLambda;
+import static org.apache.ignite.internal.configuration.asm.SchemaClassesInfo.configurationClassName;
+import static org.apache.ignite.internal.configuration.asm.SchemaClassesInfo.nodeClassName;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.isConfigValue;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.isInjectedName;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.isInternalId;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.isNamedConfigValue;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.isPolymorphicConfig;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.isPolymorphicConfigInstance;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.isPolymorphicId;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.isValue;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.polymorphicInstanceId;
+import static org.apache.ignite.internal.util.ArrayUtils.nullOrEmpty;
+import static org.apache.ignite.internal.util.CollectionUtils.concat;
+import static org.objectweb.asm.Type.getMethodType;
+import static org.objectweb.asm.Type.getType;
+
+import com.facebook.presto.bytecode.BytecodeBlock;
+import com.facebook.presto.bytecode.ClassDefinition;
+import com.facebook.presto.bytecode.FieldDefinition;
+import com.facebook.presto.bytecode.MethodDefinition;
+import com.facebook.presto.bytecode.ParameterizedType;
+import com.facebook.presto.bytecode.Variable;
+import com.facebook.presto.bytecode.expression.BytecodeExpression;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.BiFunction;
+import org.apache.ignite.configuration.ConfigurationProperty;
+import org.apache.ignite.configuration.ConfigurationTree;
+import org.apache.ignite.configuration.ConfigurationValue;
+import org.apache.ignite.configuration.ConfigurationWrongPolymorphicTypeIdException;
+import org.apache.ignite.configuration.NamedConfigurationTree;
+import org.apache.ignite.configuration.RootKey;
+import org.apache.ignite.internal.configuration.ConfigurationNode;
+import org.apache.ignite.internal.configuration.ConfigurationTreeWrapper;
+import org.apache.ignite.internal.configuration.DynamicConfiguration;
+import org.apache.ignite.internal.configuration.DynamicConfigurationChanger;
+import org.apache.ignite.internal.configuration.DynamicProperty;
+import org.apache.ignite.internal.configuration.NamedListConfiguration;
+import org.apache.ignite.internal.configuration.direct.DirectPropertyProxy;
+import org.apache.ignite.internal.configuration.tree.InnerNode;
+import org.jetbrains.annotations.Nullable;
+import org.objectweb.asm.Handle;
+import org.objectweb.asm.Opcodes;
+
+class ConfigurationImplAsmGenerator extends AbstractAsmGenerator {
+    /** Class definition that extends the {@link DynamicConfiguration}. */
+    private ClassDefinition cfgImplClassDef;
+
+    ConfigurationImplAsmGenerator(
+            ConfigurationAsmGenerator cgen,
+            Class<?> schemaClass,
+            Set<Class<?>> internalExtensions,
+            Set<Class<?>> polymorphicExtensions,
+            List<Field> schemaFields,
+            Collection<Field> internalFields,
+            Collection<Field> polymorphicFields,
+            @Nullable Field internalIdField
+    ) {
+        super(
+                cgen,
+                schemaClass,
+                internalExtensions,
+                polymorphicExtensions,
+                schemaFields,
+                internalFields,
+                polymorphicFields,
+                internalIdField
+        );
+    }
+
+    @Override
+    public List<ClassDefinition> generate() {
+        assert cfgImplClassDef == null;
+
+        List<ClassDefinition> classDefs = new ArrayList<>();
+
+        classDefs.add(createCfgImplClass());
+
+        for (Class<?> polymorphicExtension : polymorphicExtensions) {
+            // Only the fields of a specific instance of a polymorphic configuration.
+            Collection<Field> polymorphicFields = this.polymorphicFields.stream()
+                    .filter(f -> f.getDeclaringClass() == polymorphicExtension)
+                    .collect(toList());
+
+            classDefs.add(createPolymorphicExtensionCfgImplClass(polymorphicExtension, polymorphicFields));
+        }
+
+        return classDefs;
+    }
+
+    /**
+     * Construct a {@link DynamicConfiguration} definition for a configuration schema.
+     *
+     * @return Constructed {@link DynamicConfiguration} definition for the configuration schema.
+     */
+    private ClassDefinition createCfgImplClass() {
+        SchemaClassesInfo schemaClassInfo = cgen.schemaInfo(schemaClass);
+
+        // Configuration impl class definition.
+        cfgImplClassDef = new ClassDefinition(
+                of(PUBLIC, FINAL),
+                internalName(schemaClassInfo.cfgImplClassName),
+                type(DynamicConfiguration.class),
+                cgen.configClassInterfaces(schemaClass, internalExtensions)
+        );
+
+        // Fields.
+        Map<String, FieldDefinition> fieldDefs = new HashMap<>();
+
+        // To store the id of the polymorphic configuration instance.
+        FieldDefinition polymorphicTypeIdFieldDef = null;
+
+        for (Field schemaField : concat(schemaFields, internalFields, polymorphicFields)) {
+            String fieldName = fieldName(schemaField);
+
+            FieldDefinition fieldDef = addConfigurationImplField(schemaField, fieldName);
+
+            fieldDefs.put(fieldName, fieldDef);
+
+            if (isPolymorphicId(schemaField)) {
+                polymorphicTypeIdFieldDef = fieldDef;
+            }
+        }
+
+        if (internalIdField != null) {
+            // Internal id dynamic property is stored as a regular field.
+            String fieldName = internalIdField.getName();
+
+            FieldDefinition fieldDef = addConfigurationImplField(internalIdField, fieldName);
+
+            fieldDefs.put(fieldName, fieldDef);
+        }
+
+        FieldDefinition internalConfigTypesFieldDef = null;
+
+        if (!internalExtensions.isEmpty()) {
+            internalConfigTypesFieldDef = cfgImplClassDef.declareField(
+                    of(PRIVATE, FINAL),
+                    INTERNAL_CONFIG_TYPES_FIELD_NAME,
+                    Class[].class
+            );
+        }
+
+        // Constructor
+        addConfigurationImplConstructor(fieldDefs, internalConfigTypesFieldDef);
+
+        // org.apache.ignite.internal.configuration.DynamicProperty#directProxy
+        addDirectProxyMethod(schemaClassInfo);
+
+        // Getter for the internal id.
+        if (internalIdField != null) {
+            addConfigurationImplGetMethod(cfgImplClassDef, internalIdField, fieldDefs.get(internalIdField.getName()));
+        }
+
+        for (Field schemaField : concat(schemaFields, internalFields)) {
+            addConfigurationImplGetMethod(cfgImplClassDef, schemaField, fieldDefs.get(fieldName(schemaField)));
+        }
+
+        // org.apache.ignite.internal.configuration.DynamicConfiguration#configType
+        addCfgImplConfigTypeMethod(typeFromJavaClassName(schemaClassInfo.cfgClassName));
+
+        if (internalConfigTypesFieldDef != null) {
+            addCfgImplInternalConfigTypesMethod(cfgImplClassDef, internalConfigTypesFieldDef);
+        }
+
+        if (!polymorphicExtensions.isEmpty()) {
+            addCfgSpecificConfigTreeMethod(polymorphicTypeIdFieldDef);
+
+            addCfgRemoveMembersMethod(fieldDefs, polymorphicTypeIdFieldDef);
+
+            addCfgAddMembersMethod(fieldDefs, polymorphicTypeIdFieldDef);
+
+            addCfgImplPolymorphicInstanceConfigTypeMethod(polymorphicTypeIdFieldDef);
+        }
+
+        return cfgImplClassDef;
+    }
+
+    /**
+     * Declares field that corresponds to configuration value. Depending on the schema, 3 options possible:
+     * <ul>
+     *     <li>
+     *         {@code @Value public type fieldName}<br/>becomes<br/>
+     *         {@code public DynamicProperty fieldName}
+     *     </li>
+     *     <li>
+     *         {@code @ConfigValue public MyConfigurationSchema fieldName}<br/>becomes<br/>
+     *         {@code public MyConfiguration fieldName}
+     *     </li>
+     *     <li>
+     *         {@code @NamedConfigValue public type fieldName}<br/>becomes<br/>
+     *         {@code public NamedListConfiguration fieldName}
+     *     </li>
+     *     <li>
+     *         {@code @PolymorphicId public String fieldName}<br/>becomes<br/>
+     *         {@code public String fieldName}
+     *     </li>
+     * </ul>
+     *
+     * @param schemaField Configuration Schema class field.
+     * @param fieldName   Field name, if {@code null} will be used {@link Field#getName}.
+     * @return Declared field definition.
+     */
+    private FieldDefinition addConfigurationImplField(
+            Field schemaField,
+            String fieldName
+    ) {
+        ParameterizedType fieldType;
+
+        if (isConfigValue(schemaField)) {
+            fieldType = typeFromJavaClassName(cgen.schemaInfo(schemaField.getType()).cfgImplClassName);
+        } else if (isNamedConfigValue(schemaField)) {
+            fieldType = type(NamedListConfiguration.class);
+        } else {
+            fieldType = type(DynamicProperty.class);
+        }
+
+        return cfgImplClassDef.declareField(of(PUBLIC), fieldName, fieldType);
+    }
+
+    /**
+     * Implements default constructor for the configuration class. It initializes all fields and adds them to members collection.
+     *
+     * @param fieldDefs Field definitions for all fields of configuration impl class.
+     * @param internalConfigTypesFieldDef Field definition for {@link DynamicConfiguration#internalConfigTypes},
+     *      {@code null} if there are no internal extensions.
+     */
+    private void addConfigurationImplConstructor(
+            Map<String, FieldDefinition> fieldDefs,
+            @Nullable FieldDefinition internalConfigTypesFieldDef
+    ) {
+        MethodDefinition ctor = cfgImplClassDef.declareConstructor(
+                of(PUBLIC),
+                arg("prefix", List.class),
+                arg("key", String.class),
+                arg("rootKey", RootKey.class),
+                arg("changer", DynamicConfigurationChanger.class),
+                arg("listenOnly", boolean.class)
+        );
+
+        Variable rootKeyVar = ctor.getScope().getVariable("rootKey");
+        Variable changerVar = ctor.getScope().getVariable("changer");
+        Variable listenOnlyVar = ctor.getScope().getVariable("listenOnly");
+
+        SchemaClassesInfo schemaClassInfo = cgen.schemaInfo(schemaClass);
+
+        Variable thisVar = ctor.getThis();
+
+        BytecodeBlock ctorBody = ctor.getBody()
+                .append(thisVar)
+                .append(ctor.getScope().getVariable("prefix"))
+                .append(ctor.getScope().getVariable("key"))
+                .append(rootKeyVar)
+                .append(changerVar)
+                .append(listenOnlyVar)
+                .invokeConstructor(DYNAMIC_CONFIGURATION_CTOR);
+
+        BytecodeExpression thisKeysVar = thisVar.getField("keys", List.class);
+
+        // Wrap object into list to reuse the loop below.
+        List<Field> internalIdFieldAsList = internalIdField == null ? emptyList() : List.of(internalIdField);
+
+        int newIdx = 0;
+        for (Field schemaField : concat(schemaFields, internalFields, polymorphicFields, internalIdFieldAsList)) {
+            String fieldName = schemaField.getName();
+
+            BytecodeExpression newValue;
+
+            if (isValue(schemaField) || isPolymorphicId(schemaField) || isInjectedName(schemaField) || isInternalId(schemaField)) {
+                // A field with @InjectedName is special (auxiliary), it is not stored in storages as a regular field, and therefore there
+                // is no direct access to it. It is stored in the InnerNode and does not participate in its traversal, so in order to get
+                // it we need to get the InnerNode, and only then the value of this field.
+
+                // newValue = new DynamicProperty(this.keys, fieldName, rootKey, changer, listenOnly, readOnly);
+                newValue = newInstance(
+                        DynamicProperty.class,
+                        thisKeysVar,
+                        constantString(isInjectedName(schemaField) ? InnerNode.INJECTED_NAME
+                                : isInternalId(schemaField) ? InnerNode.INTERNAL_ID : schemaField.getName()),
+                        rootKeyVar,
+                        changerVar,
+                        listenOnlyVar,
+                        constantBoolean(isPolymorphicId(schemaField) || isInjectedName(schemaField) || isInternalId(schemaField))
+                );
+            } else {
+                SchemaClassesInfo fieldInfo = cgen.schemaInfo(schemaField.getType());
+
+                ParameterizedType cfgImplParameterizedType = typeFromJavaClassName(fieldInfo.cfgImplClassName);
+
+                if (isConfigValue(schemaField)) {
+                    // newValue = new MyConfigurationImpl(super.keys, fieldName, rootKey, changer, listenOnly);
+                    newValue = newInstance(
+                            cfgImplParameterizedType,
+                            thisKeysVar,
+                            constantString(fieldName),
+                            rootKeyVar,
+                            changerVar,
+                            listenOnlyVar
+                    );
+                } else {
+                    // We have to create method "$new$<idx>" to reference it in lambda expression. That's the way it
+                    // works, it'll invoke constructor with all 5 arguments, not just 2 as in BiFunction.
+                    MethodDefinition newMtd = cfgImplClassDef.declareMethod(
+                            of(PRIVATE, STATIC, SYNTHETIC),
+                            "$new$" + newIdx++,
+                            typeFromJavaClassName(fieldInfo.cfgClassName),
+                            arg("rootKey", RootKey.class),
+                            arg("changer", DynamicConfigurationChanger.class),
+                            arg("listenOnly", boolean.class),
+                            arg("prefix", List.class),
+                            arg("key", String.class)
+                    );
+
+                    // newValue = new NamedListConfiguration(this.keys, fieldName, rootKey, changer, listenOnly,
+                    //      (p, k) -> new ValueConfigurationImpl(p, k, rootKey, changer, listenOnly),
+                    //      (p, c) -> new ValueDirectProxy(p, c),
+                    //      new ValueConfigurationImpl(this.keys, "any", rootKey, changer, true)
+                    // );
+                    newValue = newInstance(
+                            NamedListConfiguration.class,
+                            thisKeysVar,
+                            constantString(fieldName),
+                            rootKeyVar,
+                            changerVar,
+                            listenOnlyVar,
+                            invokeDynamic(
+                                    LAMBDA_METAFACTORY,
+                                    asList(
+                                            getMethodType(getType(Object.class), getType(Object.class), getType(Object.class)),
+                                            new Handle(
+                                                    Opcodes.H_INVOKESTATIC,
+                                                    internalName(schemaClassInfo.cfgImplClassName),
+                                                    newMtd.getName(),
+                                                    newMtd.getMethodDescriptor(),
+                                                    false
+                                            ),
+                                            getMethodType(
+                                                    typeFromJavaClassName(fieldInfo.cfgClassName).getAsmType(),
+                                                    getType(List.class),
+                                                    getType(String.class)
+                                            )
+                                    ),
+                                    "apply",
+                                    BiFunction.class,
+                                    rootKeyVar,
+                                    changerVar,
+                                    listenOnlyVar
+                            ),
+                            newDirectProxyLambda(fieldInfo),
+                            newInstance(
+                                    cfgImplParameterizedType,
+                                    thisKeysVar,
+                                    constantString("any"),
+                                    rootKeyVar,
+                                    changerVar,
+                                    constantBoolean(true)
+                            ).cast(ConfigurationProperty.class)
+                    );
+
+                    newMtd.getBody()
+                            .append(newInstance(
+                                    cfgImplParameterizedType,
+                                    newMtd.getScope().getVariable("prefix"),
+                                    newMtd.getScope().getVariable("key"),
+                                    newMtd.getScope().getVariable("rootKey"),
+                                    newMtd.getScope().getVariable("changer"),
+                                    newMtd.getScope().getVariable("listenOnly")
+                            ))
+                            .retObject();
+                }
+            }
+
+            FieldDefinition fieldDef = fieldDefs.get(fieldName(schemaField));
+
+            // this.field = newValue;
+            ctorBody.append(thisVar.setField(fieldDef, newValue));
+
+            if (!isPolymorphicConfigInstance(schemaField.getDeclaringClass()) && !isInternalId(schemaField)) {
+                // add(this.field);
+                ctorBody.append(thisVar.invoke(DYNAMIC_CONFIGURATION_ADD_MTD, thisVar.getField(fieldDef)));
+            }
+        }
+
+        if (internalConfigTypesFieldDef != null) {
+            assert !internalExtensions.isEmpty() : cfgImplClassDef;
+
+            // Class[] tmp;
+            Variable tmpVar = ctor.getScope().createTempVariable(Class[].class);
+
+            BytecodeBlock initInternalConfigTypesField = new BytecodeBlock();
+
+            // tmp = new Class[size];
+            initInternalConfigTypesField.append(tmpVar.set(newArray(type(Class[].class), internalExtensions.size())));
+
+            int i = 0;
+
+            for (Class<?> extension : internalExtensions) {
+                // tmp[i] = InternalTableConfiguration.class;
+                initInternalConfigTypesField.append(set(
+                        tmpVar,
+                        constantInt(i++),
+                        constantClass(typeFromJavaClassName(configurationClassName(extension)))
+                ));
+            }
+
+            // this._internalConfigTypes = tmp;
+            initInternalConfigTypesField.append(setThisFieldCode(ctor, tmpVar, internalConfigTypesFieldDef));
+
+            ctorBody.append(initInternalConfigTypesField);
+        }
+
+        ctorBody.ret();
+    }
+
+    /**
+     * Generates {@link ConfigurationNode#directProxy()} method that returns new instance every time.
+     *
+     * @param schemaClassInfo Schema class info.
+     */
+    private void addDirectProxyMethod(SchemaClassesInfo schemaClassInfo) {
+        MethodDefinition methodDef = cfgImplClassDef.declareMethod(
+                of(PUBLIC), "directProxy", type(DirectPropertyProxy.class)
+        );
+
+        methodDef.getBody().append(newInstance(
+                typeFromJavaClassName(schemaClassInfo.directProxyClassName),
+                methodDef.getThis().invoke("keyPath", List.class),
+                methodDef.getThis().getField("changer", DynamicConfigurationChanger.class)
+        ));
+
+        methodDef.getBody().retObject();
+    }
+
+    /**
+     * Implements accessor method in configuration impl class.
+     *
+     * @param classDef    Configuration impl class definition.
+     * @param schemaField Configuration Schema class field.
+     * @param fieldDefs   Field definitions.

Review Comment:
   Could we clarify that this is not just 'fields', but a chain of fields, so if it's `"a", "b", "c"`, the result would be to call `this.a.b.c`?



##########
modules/configuration/src/main/java/org/apache/ignite/internal/configuration/asm/InnerNodeAsmGenerator.java:
##########
@@ -0,0 +1,1787 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.configuration.asm;
+
+import static com.facebook.presto.bytecode.Access.BRIDGE;
+import static com.facebook.presto.bytecode.Access.FINAL;
+import static com.facebook.presto.bytecode.Access.PRIVATE;
+import static com.facebook.presto.bytecode.Access.PUBLIC;
+import static com.facebook.presto.bytecode.Access.SYNTHETIC;
+import static com.facebook.presto.bytecode.Parameter.arg;
+import static com.facebook.presto.bytecode.ParameterizedType.type;
+import static com.facebook.presto.bytecode.ParameterizedType.typeFromJavaClassName;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.constantClass;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.constantInt;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.constantNull;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.constantString;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.inlineIf;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.invokeStatic;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.isNotNull;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.isNull;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.newArray;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.newInstance;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.not;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.set;
+import static java.util.Collections.singleton;
+import static java.util.EnumSet.of;
+import static java.util.function.Function.identity;
+import static java.util.stream.Collectors.toList;
+import static java.util.stream.Collectors.toMap;
+import static org.apache.ignite.internal.configuration.asm.ConfigurationAsmGenerator.box;
+import static org.apache.ignite.internal.configuration.asm.ConfigurationAsmGenerator.changeMethodName;
+import static org.apache.ignite.internal.configuration.asm.ConfigurationAsmGenerator.fieldName;
+import static org.apache.ignite.internal.configuration.asm.ConfigurationAsmGenerator.getThisFieldCode;
+import static org.apache.ignite.internal.configuration.asm.ConfigurationAsmGenerator.internalName;
+import static org.apache.ignite.internal.configuration.asm.ConfigurationAsmGenerator.nodeClassInterfaces;
+import static org.apache.ignite.internal.configuration.asm.ConfigurationAsmGenerator.polymorphicIdField;
+import static org.apache.ignite.internal.configuration.asm.ConfigurationAsmGenerator.setThisFieldCode;
+import static org.apache.ignite.internal.configuration.asm.ConfigurationAsmGenerator.throwException;
+import static org.apache.ignite.internal.configuration.asm.ConfigurationAsmGenerator.typeIdSwitchBuilder;
+import static org.apache.ignite.internal.configuration.asm.SchemaClassesInfo.changeClassName;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.containsNameAnnotation;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.hasDefault;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.isConfigValue;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.isInjectedName;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.isNamedConfigValue;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.isPolymorphicConfig;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.isPolymorphicConfigInstance;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.isPolymorphicId;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.isValue;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.polymorphicInstanceId;
+import static org.apache.ignite.internal.util.CollectionUtils.concat;
+
+import com.facebook.presto.bytecode.BytecodeBlock;
+import com.facebook.presto.bytecode.BytecodeNode;
+import com.facebook.presto.bytecode.ClassDefinition;
+import com.facebook.presto.bytecode.FieldDefinition;
+import com.facebook.presto.bytecode.MethodDefinition;
+import com.facebook.presto.bytecode.ParameterizedType;
+import com.facebook.presto.bytecode.Variable;
+import com.facebook.presto.bytecode.control.IfStatement;
+import com.facebook.presto.bytecode.expression.BytecodeExpression;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.UUID;
+import java.util.function.BiFunction;
+import java.util.function.Consumer;
+import java.util.function.Function;
+import org.apache.ignite.configuration.ConfigurationWrongPolymorphicTypeIdException;
+import org.apache.ignite.configuration.NamedListView;
+import org.apache.ignite.configuration.annotation.AbstractConfiguration;
+import org.apache.ignite.configuration.annotation.InjectedName;
+import org.apache.ignite.configuration.annotation.Name;
+import org.apache.ignite.configuration.annotation.PolymorphicConfig;
+import org.apache.ignite.configuration.annotation.PolymorphicId;
+import org.apache.ignite.internal.configuration.tree.ConfigurationSource;
+import org.apache.ignite.internal.configuration.tree.ConfigurationVisitor;
+import org.apache.ignite.internal.configuration.tree.ConstructableTreeNode;
+import org.apache.ignite.internal.configuration.tree.InnerNode;
+import org.apache.ignite.internal.configuration.tree.NamedListNode;
+import org.apache.ignite.internal.configuration.util.ConfigurationUtil;
+import org.apache.ignite.internal.util.ArrayUtils;
+import org.jetbrains.annotations.Nullable;
+
+//TODO Simplify code generation process: https://issues.apache.org/jira/browse/IGNITE-18366
+class InnerNodeAsmGenerator extends AbstractAsmGenerator {
+    /** Class definition that extends the {@link InnerNode}. */
+    private ClassDefinition innerNodeClassDef;
+
+    InnerNodeAsmGenerator(
+            ConfigurationAsmGenerator cgen,
+            Class<?> schemaClass,
+            Set<Class<?>> internalExtensions,
+            Set<Class<?>> polymorphicExtensions,
+            List<Field> schemaFields,
+            Collection<Field> internalFields,
+            Collection<Field> polymorphicFields,
+            @Nullable Field internalIdField
+    ) {
+        super(
+                cgen,
+                schemaClass,
+                internalExtensions,
+                polymorphicExtensions,
+                schemaFields,
+                internalFields,
+                polymorphicFields,
+                internalIdField
+        );
+    }
+
+    @Override
+    public List<ClassDefinition> generate() {
+        assert innerNodeClassDef == null;
+
+        List<ClassDefinition> classDefs = new ArrayList<>();
+
+        classDefs.add(createNodeClass());
+
+        for (Class<?> polymorphicExtension : polymorphicExtensions) {
+            // Only the fields of a specific instance of a polymorphic configuration.
+            Collection<Field> polymorphicFields = this.polymorphicFields.stream()
+                    .filter(f -> f.getDeclaringClass() == polymorphicExtension)
+                    .collect(toList());
+
+            classDefs.add(createPolymorphicExtensionNodeClass(polymorphicExtension, polymorphicFields));
+        }
+
+        return classDefs;
+    }
+
+
+    /**
+     * Construct a {@link InnerNode} definition for a configuration schema.
+     *
+     * @return Constructed {@link InnerNode} definition for the configuration schema.
+     */
+    private ClassDefinition createNodeClass() {
+        SchemaClassesInfo schemaClassInfo = cgen.schemaInfo(schemaClass);
+
+        // Node class definition.
+        innerNodeClassDef = new ClassDefinition(
+                of(PUBLIC, FINAL),
+                internalName(schemaClassInfo.nodeClassName),
+                type(InnerNode.class),
+                nodeClassInterfaces(schemaClass, internalExtensions)
+        );
+
+        // Spec fields.
+        Map<Class<?>, FieldDefinition> specFields = new HashMap<>();
+
+        int i = 0;
+
+        for (Class<?> clazz : concat(List.of(schemaClass), internalExtensions, polymorphicExtensions)) {
+            specFields.put(clazz, innerNodeClassDef.declareField(of(PRIVATE, FINAL), "_spec" + i++, clazz));
+        }
+
+        // Define the rest of the fields.
+        Map<String, FieldDefinition> fieldDefs = new HashMap<>();
+
+        // To store the id of the polymorphic configuration instance.
+        FieldDefinition polymorphicTypeIdFieldDef = null;
+
+        // Field with @InjectedName.
+        FieldDefinition injectedNameFieldDef = null;
+
+        for (Field schemaField : concat(schemaFields, internalFields, polymorphicFields)) {
+            FieldDefinition fieldDef = addInnerNodeField(schemaField);
+
+            fieldDefs.put(fieldDef.getName(), fieldDef);
+
+            if (isPolymorphicId(schemaField)) {
+                polymorphicTypeIdFieldDef = fieldDef;
+            } else if (isInjectedName(schemaField)) {
+                injectedNameFieldDef = fieldDef;
+            }
+        }
+
+        // org.apache.ignite.internal.configuration.tree.InnerNode#schemaType
+        addNodeSchemaTypeMethod(polymorphicTypeIdFieldDef);
+
+        FieldDefinition internalSchemaTypesFieldDef = null;
+
+        if (!internalExtensions.isEmpty()) {
+            internalSchemaTypesFieldDef = innerNodeClassDef.declareField(
+                    of(PRIVATE, FINAL),
+                    "_" + INTERNAL_SCHEMA_TYPES_MTD.getName(),
+                    Class[].class
+            );
+        }
+
+        // Constructor.
+        addNodeConstructor(
+                specFields,
+                fieldDefs,
+                internalSchemaTypesFieldDef
+        );
+
+        // Add view method for internal id.
+        if (internalIdField != null) {
+            addNodeInternalIdMethod();
+        }
+
+        // VIEW and CHANGE methods.
+        for (Field schemaField : concat(schemaFields, internalFields)) {
+            String fieldName = schemaField.getName();
+
+            FieldDefinition fieldDef = fieldDefs.get(fieldName);
+
+            addNodeViewMethod(
+                    innerNodeClassDef,
+                    schemaField,
+                    viewMtd -> getThisFieldCode(viewMtd, fieldDef),
+                    null
+            );
+
+            // Read only.
+            if (isPolymorphicId(schemaField) || isInjectedName(schemaField)) {
+                continue;
+            }
+
+            // Add change methods.
+            MethodDefinition changeMtd0 = addNodeChangeMethod(
+                    innerNodeClassDef,
+                    schemaField,
+                    changeMtd -> getThisFieldCode(changeMtd, fieldDef),
+                    (changeMtd, newValue) -> setThisFieldCode(changeMtd, newValue, fieldDef),
+                    null
+            );
+
+            addNodeChangeBridgeMethod(innerNodeClassDef, changeClassName(schemaField.getDeclaringClass()), changeMtd0);
+        }
+
+        Map<Class<?>, List<Field>> polymorphicFieldsByExtension = Map.of();
+
+        MethodDefinition changePolymorphicTypeIdMtd = null;
+
+        if (!polymorphicExtensions.isEmpty()) {
+            assert polymorphicTypeIdFieldDef != null : schemaClass.getName();
+
+            addNodeSpecificNodeMethod(polymorphicTypeIdFieldDef);
+
+            changePolymorphicTypeIdMtd = addNodeChangePolymorphicTypeIdMethod(fieldDefs, polymorphicTypeIdFieldDef);
+
+            addNodeConvertMethods(changePolymorphicTypeIdMtd);
+
+            polymorphicFieldsByExtension = new LinkedHashMap<>();
+
+            for (Class<?> polymorphicExtension : polymorphicExtensions) {
+                polymorphicFieldsByExtension.put(
+                        polymorphicExtension,
+                        polymorphicFields.stream()
+                                .filter(f -> polymorphicExtension.equals(f.getDeclaringClass()))
+                                .collect(toList())
+                );
+            }
+        }
+
+        // traverseChildren
+        addNodeTraverseChildrenMethod(
+                fieldDefs,
+                polymorphicFieldsByExtension,
+                polymorphicTypeIdFieldDef
+        );
+
+        // traverseChild
+        addNodeTraverseChildMethod(
+                fieldDefs,
+                polymorphicFieldsByExtension,
+                polymorphicTypeIdFieldDef
+        );
+
+        // construct
+        addNodeConstructMethod(
+                fieldDefs,
+                polymorphicFieldsByExtension,
+                polymorphicTypeIdFieldDef,
+                changePolymorphicTypeIdMtd
+        );
+
+        // constructDefault
+        addNodeConstructDefaultMethod(
+                specFields,
+                fieldDefs,
+                polymorphicFieldsByExtension,
+                polymorphicTypeIdFieldDef
+        );
+
+        if (injectedNameFieldDef != null) {
+            addInjectedNameFieldMethods(injectedNameFieldDef);
+        }
+
+        if (polymorphicTypeIdFieldDef != null) {
+            addIsPolymorphicMethod();
+        }
+
+        if (internalSchemaTypesFieldDef != null) {
+            addInternalSchemaTypesMethod(internalSchemaTypesFieldDef);
+        }
+
+        if (schemaClass.getSuperclass().isAnnotationPresent(AbstractConfiguration.class)) {
+            addIsExtendAbstractConfigurationMethod();
+        }
+
+        return innerNodeClassDef;
+    }
+
+    /**
+     * Add {@link InnerNode#schemaType} method implementation to the class.
+     *
+     * @param polymorphicTypeIdFieldDef Identification field for the polymorphic configuration instance.
+     */
+    private void addNodeSchemaTypeMethod(@Nullable FieldDefinition polymorphicTypeIdFieldDef) {
+        MethodDefinition schemaTypeMtd = innerNodeClassDef.declareMethod(
+                of(PUBLIC),
+                "schemaType",
+                type(Class.class)
+        );
+
+        BytecodeBlock mtdBody = schemaTypeMtd.getBody();
+
+        if (polymorphicExtensions.isEmpty()) {
+            mtdBody.append(constantClass(schemaClass)).retObject();
+        } else {
+            assert polymorphicTypeIdFieldDef != null : innerNodeClassDef.getName();
+
+            StringSwitchBuilder switchBuilderTypeId = typeIdSwitchBuilder(schemaTypeMtd, polymorphicTypeIdFieldDef);
+
+            for (Class<?> polymorphicExtension : polymorphicExtensions) {
+                switchBuilderTypeId.addCase(
+                        polymorphicInstanceId(polymorphicExtension),
+                        constantClass(polymorphicExtension).ret()
+                );
+            }
+
+            mtdBody.append(switchBuilderTypeId.build());
+        }
+    }
+
+    /**
+     * Declares field that corresponds to configuration value. Depending on the schema, 5 options possible:

Review Comment:
   ```suggestion
        * Declares a field that corresponds to configuration value. Depending on the schema, 5 options are possible:
   ```



##########
modules/configuration/src/main/java/org/apache/ignite/internal/configuration/asm/AbstractAsmGenerator.java:
##########
@@ -0,0 +1,285 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.configuration.asm;
+
+import com.facebook.presto.bytecode.ClassDefinition;
+import java.io.Serializable;
+import java.lang.invoke.LambdaMetafactory;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles.Lookup;
+import java.lang.invoke.MethodType;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.function.Consumer;
+import org.apache.ignite.configuration.ConfigurationProperty;
+import org.apache.ignite.configuration.RootKey;
+import org.apache.ignite.internal.configuration.ConfigurationNode;
+import org.apache.ignite.internal.configuration.DynamicConfiguration;
+import org.apache.ignite.internal.configuration.DynamicConfigurationChanger;
+import org.apache.ignite.internal.configuration.direct.DirectConfigurationProxy;
+import org.apache.ignite.internal.configuration.tree.ConfigurationSource;
+import org.apache.ignite.internal.configuration.tree.ConfigurationVisitor;
+import org.apache.ignite.internal.configuration.tree.ConstructableTreeNode;
+import org.apache.ignite.internal.configuration.tree.InnerNode;
+import org.apache.ignite.internal.configuration.tree.NamedListNode;
+import org.apache.ignite.internal.configuration.util.ConfigurationUtil;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * Class that holds constants and commonly used fields for generators.
+ */
+abstract class AbstractAsmGenerator {
+    /** {@link DynamicConfiguration#DynamicConfiguration} constructor. */
+    static final Constructor<?> DYNAMIC_CONFIGURATION_CTOR;
+
+    /** {@link LambdaMetafactory#metafactory(Lookup, String, MethodType, MethodType, MethodHandle, MethodType)}. */
+    static final Method LAMBDA_METAFACTORY;
+
+    /** {@link Consumer#accept(Object)}. */
+    static final Method ACCEPT;
+
+    /** {@link ConfigurationVisitor#visitLeafNode(String, Serializable)}. */
+    static final Method VISIT_LEAF;
+
+    /** {@link ConfigurationVisitor#visitInnerNode(String, InnerNode)}. */
+    static final Method VISIT_INNER;
+
+    /** {@link ConfigurationVisitor#visitNamedListNode(String, NamedListNode)}. */
+    static final Method VISIT_NAMED;
+
+    /** {@link ConfigurationSource#unwrap(Class)}. */
+    static final Method UNWRAP;
+
+    /** {@link ConfigurationSource#descend(ConstructableTreeNode)}. */
+    static final Method DESCEND;
+
+    /** {@link ConstructableTreeNode#copy()}. */
+    static final Method COPY;
+
+    /** {@link InnerNode#internalId()}. */
+    static final Method INTERNAL_ID;
+
+    /** {@code DynamicConfiguration#add} method. */
+    static final Method DYNAMIC_CONFIGURATION_ADD_MTD;
+
+    /** {@link Objects#requireNonNull(Object, String)}. */
+    static final Method REQUIRE_NON_NULL;
+
+    /** {@link Class#getName} method. */
+    static final Method CLASS_GET_NAME_MTD;
+
+    /** {@link String#equals} method. */
+    static final Method STRING_EQUALS_MTD;
+
+    /** {@link ConfigurationSource#polymorphicTypeId} method. */
+    static final Method POLYMORPHIC_TYPE_ID_MTD;
+
+    /** {@link InnerNode#constructDefault} method. */
+    static final Method CONSTRUCT_DEFAULT_MTD;
+
+    /** {@code ConfigurationNode#refreshValue} method. */
+    static final Method REFRESH_VALUE_MTD;
+
+    /** {@code DynamicConfiguration#addMember} method. */
+    static final Method ADD_MEMBER_MTD;
+
+    /** {@code DynamicConfiguration#removeMember} method. */
+    static final Method REMOVE_MEMBER_MTD;
+
+    /** {@link InnerNode#specificNode} method. */
+    static final Method SPECIFIC_NODE_MTD;
+
+    /** {@link DynamicConfiguration#specificConfigTree} method. */
+    static final Method SPECIFIC_CONFIG_TREE_MTD;
+
+    /** {@link ConfigurationUtil#addDefaults}. */
+    static final Method ADD_DEFAULTS_MTD;
+
+    /** {@link InnerNode#setInjectedNameFieldValue}. */
+    static final Method SET_INJECTED_NAME_FIELD_VALUE_MTD;
+
+    /** {@code ConfigurationNode#currentValue}. */
+    static final Method CURRENT_VALUE_MTD;
+
+    /** {@link DynamicConfiguration#isRemovedFromNamedList}. */
+    static final Method IS_REMOVED_FROM_NAMED_LIST_MTD;
+
+    /** {@link InnerNode#isPolymorphic}. */
+    static final Method IS_POLYMORPHIC_MTD;
+
+    /** {@link InnerNode#internalSchemaTypes}. */
+    static final Method INTERNAL_SCHEMA_TYPES_MTD;
+
+    /** {@code Node#convert} method name. */
+    static final String CONVERT_MTD_NAME = "convert";
+
+    /** {@link ConstructableTreeNode#construct(String, ConfigurationSource, boolean)} method name. */
+    static final String CONSTRUCT_MTD_NAME = "construct";
+
+    /** Field name for method {@link DynamicConfiguration#internalConfigTypes}. */
+    static final String INTERNAL_CONFIG_TYPES_FIELD_NAME = "_internalConfigTypes";
+
+    /** {@link DirectConfigurationProxy#DirectConfigurationProxy(List, DynamicConfigurationChanger)}. */
+    static final Constructor<?> DIRECT_CFG_CTOR;
+
+    /** {@link ConfigurationUtil#appendKey(List, Object)}. */
+    static final Method APPEND_KEY;

Review Comment:
   Are you sure it's a good idea to put everything in this single class? For example, `APPEND_KEY` is only used by `DirectProxyAsmGenerator`, so shouldn't this field belong to it?



##########
modules/configuration/src/main/java/org/apache/ignite/internal/configuration/asm/ConfigurationImplAsmGenerator.java:
##########
@@ -0,0 +1,872 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.configuration.asm;
+
+import static com.facebook.presto.bytecode.Access.FINAL;
+import static com.facebook.presto.bytecode.Access.PRIVATE;
+import static com.facebook.presto.bytecode.Access.PUBLIC;
+import static com.facebook.presto.bytecode.Access.STATIC;
+import static com.facebook.presto.bytecode.Access.SYNTHETIC;
+import static com.facebook.presto.bytecode.Parameter.arg;
+import static com.facebook.presto.bytecode.ParameterizedType.type;
+import static com.facebook.presto.bytecode.ParameterizedType.typeFromJavaClassName;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.constantBoolean;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.constantClass;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.constantInt;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.constantString;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.inlineIf;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.invokeDynamic;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.newArray;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.newInstance;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.set;
+import static java.util.Arrays.asList;
+import static java.util.Collections.emptyList;
+import static java.util.EnumSet.of;
+import static java.util.function.Function.identity;
+import static java.util.stream.Collectors.toList;
+import static java.util.stream.Collectors.toMap;
+import static org.apache.ignite.internal.configuration.asm.ConfigurationAsmGenerator.fieldName;
+import static org.apache.ignite.internal.configuration.asm.ConfigurationAsmGenerator.getThisFieldCode;
+import static org.apache.ignite.internal.configuration.asm.ConfigurationAsmGenerator.internalName;
+import static org.apache.ignite.internal.configuration.asm.ConfigurationAsmGenerator.setThisFieldCode;
+import static org.apache.ignite.internal.configuration.asm.ConfigurationAsmGenerator.throwException;
+import static org.apache.ignite.internal.configuration.asm.DirectProxyAsmGenerator.newDirectProxyLambda;
+import static org.apache.ignite.internal.configuration.asm.SchemaClassesInfo.configurationClassName;
+import static org.apache.ignite.internal.configuration.asm.SchemaClassesInfo.nodeClassName;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.isConfigValue;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.isInjectedName;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.isInternalId;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.isNamedConfigValue;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.isPolymorphicConfig;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.isPolymorphicConfigInstance;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.isPolymorphicId;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.isValue;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.polymorphicInstanceId;
+import static org.apache.ignite.internal.util.ArrayUtils.nullOrEmpty;
+import static org.apache.ignite.internal.util.CollectionUtils.concat;
+import static org.objectweb.asm.Type.getMethodType;
+import static org.objectweb.asm.Type.getType;
+
+import com.facebook.presto.bytecode.BytecodeBlock;
+import com.facebook.presto.bytecode.ClassDefinition;
+import com.facebook.presto.bytecode.FieldDefinition;
+import com.facebook.presto.bytecode.MethodDefinition;
+import com.facebook.presto.bytecode.ParameterizedType;
+import com.facebook.presto.bytecode.Variable;
+import com.facebook.presto.bytecode.expression.BytecodeExpression;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.BiFunction;
+import org.apache.ignite.configuration.ConfigurationProperty;
+import org.apache.ignite.configuration.ConfigurationTree;
+import org.apache.ignite.configuration.ConfigurationValue;
+import org.apache.ignite.configuration.ConfigurationWrongPolymorphicTypeIdException;
+import org.apache.ignite.configuration.NamedConfigurationTree;
+import org.apache.ignite.configuration.RootKey;
+import org.apache.ignite.internal.configuration.ConfigurationNode;
+import org.apache.ignite.internal.configuration.ConfigurationTreeWrapper;
+import org.apache.ignite.internal.configuration.DynamicConfiguration;
+import org.apache.ignite.internal.configuration.DynamicConfigurationChanger;
+import org.apache.ignite.internal.configuration.DynamicProperty;
+import org.apache.ignite.internal.configuration.NamedListConfiguration;
+import org.apache.ignite.internal.configuration.direct.DirectPropertyProxy;
+import org.apache.ignite.internal.configuration.tree.InnerNode;
+import org.jetbrains.annotations.Nullable;
+import org.objectweb.asm.Handle;
+import org.objectweb.asm.Opcodes;
+
+class ConfigurationImplAsmGenerator extends AbstractAsmGenerator {
+    /** Class definition that extends the {@link DynamicConfiguration}. */
+    private ClassDefinition cfgImplClassDef;
+
+    ConfigurationImplAsmGenerator(
+            ConfigurationAsmGenerator cgen,
+            Class<?> schemaClass,
+            Set<Class<?>> internalExtensions,
+            Set<Class<?>> polymorphicExtensions,
+            List<Field> schemaFields,
+            Collection<Field> internalFields,
+            Collection<Field> polymorphicFields,
+            @Nullable Field internalIdField
+    ) {
+        super(
+                cgen,
+                schemaClass,
+                internalExtensions,
+                polymorphicExtensions,
+                schemaFields,
+                internalFields,
+                polymorphicFields,
+                internalIdField
+        );
+    }
+
+    @Override
+    public List<ClassDefinition> generate() {
+        assert cfgImplClassDef == null;
+
+        List<ClassDefinition> classDefs = new ArrayList<>();
+
+        classDefs.add(createCfgImplClass());
+
+        for (Class<?> polymorphicExtension : polymorphicExtensions) {
+            // Only the fields of a specific instance of a polymorphic configuration.
+            Collection<Field> polymorphicFields = this.polymorphicFields.stream()
+                    .filter(f -> f.getDeclaringClass() == polymorphicExtension)
+                    .collect(toList());
+
+            classDefs.add(createPolymorphicExtensionCfgImplClass(polymorphicExtension, polymorphicFields));
+        }
+
+        return classDefs;
+    }
+
+    /**
+     * Construct a {@link DynamicConfiguration} definition for a configuration schema.
+     *
+     * @return Constructed {@link DynamicConfiguration} definition for the configuration schema.
+     */
+    private ClassDefinition createCfgImplClass() {
+        SchemaClassesInfo schemaClassInfo = cgen.schemaInfo(schemaClass);
+
+        // Configuration impl class definition.
+        cfgImplClassDef = new ClassDefinition(
+                of(PUBLIC, FINAL),
+                internalName(schemaClassInfo.cfgImplClassName),
+                type(DynamicConfiguration.class),
+                cgen.configClassInterfaces(schemaClass, internalExtensions)
+        );
+
+        // Fields.
+        Map<String, FieldDefinition> fieldDefs = new HashMap<>();
+
+        // To store the id of the polymorphic configuration instance.
+        FieldDefinition polymorphicTypeIdFieldDef = null;
+
+        for (Field schemaField : concat(schemaFields, internalFields, polymorphicFields)) {
+            String fieldName = fieldName(schemaField);
+
+            FieldDefinition fieldDef = addConfigurationImplField(schemaField, fieldName);
+
+            fieldDefs.put(fieldName, fieldDef);
+
+            if (isPolymorphicId(schemaField)) {
+                polymorphicTypeIdFieldDef = fieldDef;
+            }
+        }
+
+        if (internalIdField != null) {
+            // Internal id dynamic property is stored as a regular field.
+            String fieldName = internalIdField.getName();
+
+            FieldDefinition fieldDef = addConfigurationImplField(internalIdField, fieldName);
+
+            fieldDefs.put(fieldName, fieldDef);
+        }
+
+        FieldDefinition internalConfigTypesFieldDef = null;
+
+        if (!internalExtensions.isEmpty()) {
+            internalConfigTypesFieldDef = cfgImplClassDef.declareField(
+                    of(PRIVATE, FINAL),
+                    INTERNAL_CONFIG_TYPES_FIELD_NAME,
+                    Class[].class
+            );
+        }
+
+        // Constructor
+        addConfigurationImplConstructor(fieldDefs, internalConfigTypesFieldDef);
+
+        // org.apache.ignite.internal.configuration.DynamicProperty#directProxy
+        addDirectProxyMethod(schemaClassInfo);
+
+        // Getter for the internal id.
+        if (internalIdField != null) {
+            addConfigurationImplGetMethod(cfgImplClassDef, internalIdField, fieldDefs.get(internalIdField.getName()));
+        }
+
+        for (Field schemaField : concat(schemaFields, internalFields)) {
+            addConfigurationImplGetMethod(cfgImplClassDef, schemaField, fieldDefs.get(fieldName(schemaField)));
+        }
+
+        // org.apache.ignite.internal.configuration.DynamicConfiguration#configType
+        addCfgImplConfigTypeMethod(typeFromJavaClassName(schemaClassInfo.cfgClassName));
+
+        if (internalConfigTypesFieldDef != null) {
+            addCfgImplInternalConfigTypesMethod(cfgImplClassDef, internalConfigTypesFieldDef);
+        }
+
+        if (!polymorphicExtensions.isEmpty()) {
+            addCfgSpecificConfigTreeMethod(polymorphicTypeIdFieldDef);
+
+            addCfgRemoveMembersMethod(fieldDefs, polymorphicTypeIdFieldDef);
+
+            addCfgAddMembersMethod(fieldDefs, polymorphicTypeIdFieldDef);
+
+            addCfgImplPolymorphicInstanceConfigTypeMethod(polymorphicTypeIdFieldDef);
+        }
+
+        return cfgImplClassDef;
+    }
+
+    /**
+     * Declares field that corresponds to configuration value. Depending on the schema, 3 options possible:

Review Comment:
   ```suggestion
        * Declares a field that corresponds to configuration value. Depending on the schema, the following options are possible:
   ```



##########
modules/configuration/src/main/java/org/apache/ignite/internal/configuration/asm/ConfigurationAsmGenerator.java:
##########
@@ -3251,7 +486,7 @@ private static StringSwitchBuilder typeIdSwitchBuilder(MethodDefinition mtdDef,
      * @param fieldDefs Field definitions.

Review Comment:
   Could we clarify that this is not just 'fields', but a chain of fields, so if it's `"a", "b", "c"`, the result would be to call `this.a.b.c`?



##########
modules/configuration/src/main/java/org/apache/ignite/internal/configuration/asm/ConfigurationImplAsmGenerator.java:
##########
@@ -0,0 +1,872 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.configuration.asm;
+
+import static com.facebook.presto.bytecode.Access.FINAL;
+import static com.facebook.presto.bytecode.Access.PRIVATE;
+import static com.facebook.presto.bytecode.Access.PUBLIC;
+import static com.facebook.presto.bytecode.Access.STATIC;
+import static com.facebook.presto.bytecode.Access.SYNTHETIC;
+import static com.facebook.presto.bytecode.Parameter.arg;
+import static com.facebook.presto.bytecode.ParameterizedType.type;
+import static com.facebook.presto.bytecode.ParameterizedType.typeFromJavaClassName;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.constantBoolean;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.constantClass;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.constantInt;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.constantString;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.inlineIf;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.invokeDynamic;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.newArray;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.newInstance;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.set;
+import static java.util.Arrays.asList;
+import static java.util.Collections.emptyList;
+import static java.util.EnumSet.of;
+import static java.util.function.Function.identity;
+import static java.util.stream.Collectors.toList;
+import static java.util.stream.Collectors.toMap;
+import static org.apache.ignite.internal.configuration.asm.ConfigurationAsmGenerator.fieldName;
+import static org.apache.ignite.internal.configuration.asm.ConfigurationAsmGenerator.getThisFieldCode;
+import static org.apache.ignite.internal.configuration.asm.ConfigurationAsmGenerator.internalName;
+import static org.apache.ignite.internal.configuration.asm.ConfigurationAsmGenerator.setThisFieldCode;
+import static org.apache.ignite.internal.configuration.asm.ConfigurationAsmGenerator.throwException;
+import static org.apache.ignite.internal.configuration.asm.DirectProxyAsmGenerator.newDirectProxyLambda;
+import static org.apache.ignite.internal.configuration.asm.SchemaClassesInfo.configurationClassName;
+import static org.apache.ignite.internal.configuration.asm.SchemaClassesInfo.nodeClassName;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.isConfigValue;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.isInjectedName;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.isInternalId;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.isNamedConfigValue;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.isPolymorphicConfig;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.isPolymorphicConfigInstance;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.isPolymorphicId;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.isValue;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.polymorphicInstanceId;
+import static org.apache.ignite.internal.util.ArrayUtils.nullOrEmpty;
+import static org.apache.ignite.internal.util.CollectionUtils.concat;
+import static org.objectweb.asm.Type.getMethodType;
+import static org.objectweb.asm.Type.getType;
+
+import com.facebook.presto.bytecode.BytecodeBlock;
+import com.facebook.presto.bytecode.ClassDefinition;
+import com.facebook.presto.bytecode.FieldDefinition;
+import com.facebook.presto.bytecode.MethodDefinition;
+import com.facebook.presto.bytecode.ParameterizedType;
+import com.facebook.presto.bytecode.Variable;
+import com.facebook.presto.bytecode.expression.BytecodeExpression;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.BiFunction;
+import org.apache.ignite.configuration.ConfigurationProperty;
+import org.apache.ignite.configuration.ConfigurationTree;
+import org.apache.ignite.configuration.ConfigurationValue;
+import org.apache.ignite.configuration.ConfigurationWrongPolymorphicTypeIdException;
+import org.apache.ignite.configuration.NamedConfigurationTree;
+import org.apache.ignite.configuration.RootKey;
+import org.apache.ignite.internal.configuration.ConfigurationNode;
+import org.apache.ignite.internal.configuration.ConfigurationTreeWrapper;
+import org.apache.ignite.internal.configuration.DynamicConfiguration;
+import org.apache.ignite.internal.configuration.DynamicConfigurationChanger;
+import org.apache.ignite.internal.configuration.DynamicProperty;
+import org.apache.ignite.internal.configuration.NamedListConfiguration;
+import org.apache.ignite.internal.configuration.direct.DirectPropertyProxy;
+import org.apache.ignite.internal.configuration.tree.InnerNode;
+import org.jetbrains.annotations.Nullable;
+import org.objectweb.asm.Handle;
+import org.objectweb.asm.Opcodes;
+
+class ConfigurationImplAsmGenerator extends AbstractAsmGenerator {
+    /** Class definition that extends the {@link DynamicConfiguration}. */
+    private ClassDefinition cfgImplClassDef;
+
+    ConfigurationImplAsmGenerator(
+            ConfigurationAsmGenerator cgen,
+            Class<?> schemaClass,
+            Set<Class<?>> internalExtensions,
+            Set<Class<?>> polymorphicExtensions,
+            List<Field> schemaFields,
+            Collection<Field> internalFields,
+            Collection<Field> polymorphicFields,
+            @Nullable Field internalIdField
+    ) {
+        super(
+                cgen,
+                schemaClass,
+                internalExtensions,
+                polymorphicExtensions,
+                schemaFields,
+                internalFields,
+                polymorphicFields,
+                internalIdField
+        );
+    }
+
+    @Override
+    public List<ClassDefinition> generate() {
+        assert cfgImplClassDef == null;
+
+        List<ClassDefinition> classDefs = new ArrayList<>();
+
+        classDefs.add(createCfgImplClass());
+
+        for (Class<?> polymorphicExtension : polymorphicExtensions) {
+            // Only the fields of a specific instance of a polymorphic configuration.
+            Collection<Field> polymorphicFields = this.polymorphicFields.stream()
+                    .filter(f -> f.getDeclaringClass() == polymorphicExtension)
+                    .collect(toList());
+
+            classDefs.add(createPolymorphicExtensionCfgImplClass(polymorphicExtension, polymorphicFields));
+        }
+
+        return classDefs;
+    }
+
+    /**
+     * Construct a {@link DynamicConfiguration} definition for a configuration schema.
+     *
+     * @return Constructed {@link DynamicConfiguration} definition for the configuration schema.
+     */
+    private ClassDefinition createCfgImplClass() {
+        SchemaClassesInfo schemaClassInfo = cgen.schemaInfo(schemaClass);
+
+        // Configuration impl class definition.
+        cfgImplClassDef = new ClassDefinition(
+                of(PUBLIC, FINAL),

Review Comment:
   `EnumSet.of` does not seem to be a good candidate for static importing. `EnumSet.of(x, y)` reads naturally (literally - 'enum set of ...'), causes no confusion and is not clumsy; `of(x, y)` makes a reader scroll to imports section of ask for an IDE support to understand what's going on.
   
   I suggest to not import it statically.



##########
modules/configuration/src/main/java/org/apache/ignite/internal/configuration/asm/ConfigurationAsmGenerator.java:
##########
@@ -570,1669 +312,116 @@ private Field internalIdField(Class<?> schemaClass, Set<Class<?>> schemaExtensio
     }
 
     /**
-     * Construct a {@link InnerNode} definition for a configuration schema.
+     * Copies field into itself or instantiates it if the field is null. Code like: {@code this.field == null ? new ValueNode() :
+     * (ValueNode)this.field.copy();}.
      *
-     * @param schemaClass           Configuration schema class.
-     * @param internalExtensions    Internal extensions of the configuration schema.
-     * @param polymorphicExtensions Polymorphic extensions of the configuration schema.
-     * @param schemaFields          Fields of the schema class.
-     * @param internalFields        Fields of internal extensions of the configuration schema.
-     * @param polymorphicFields     Fields of polymorphic extensions of the configuration schema.
-     * @param internalIdField       Internal id field or {@code null} if it's not present.
-     * @return Constructed {@link InnerNode} definition for the configuration schema.
+     * @param schemaField  Configuration schema class field.
+     * @param getFieldCode Bytecode of getting the field, for example: {@code this.field} or {@code this.field.field};
+     * @return Bytecode expression.
      */
-    private ClassDefinition createNodeClass(
-            Class<?> schemaClass,
-            Set<Class<?>> internalExtensions,
-            Set<Class<?>> polymorphicExtensions,
-            List<Field> schemaFields,
-            Collection<Field> internalFields,
-            Collection<Field> polymorphicFields,
-            @Nullable Field internalIdField
-    ) {
-        SchemaClassesInfo schemaClassInfo = schemasInfo.get(schemaClass);
-
-        // Node class definition.
-        ClassDefinition classDef = new ClassDefinition(
-                of(PUBLIC, FINAL),
-                internalName(schemaClassInfo.nodeClassName),
-                type(InnerNode.class),
-                nodeClassInterfaces(schemaClass, internalExtensions)
-        );
-
-        // Spec fields.
-        Map<Class<?>, FieldDefinition> specFields = new HashMap<>();
-
-        int i = 0;
-
-        for (Class<?> clazz : concat(List.of(schemaClass), internalExtensions, polymorphicExtensions)) {
-            specFields.put(clazz, classDef.declareField(of(PRIVATE, FINAL), "_spec" + i++, clazz));
-        }
-
-        // Define the rest of the fields.
-        Map<String, FieldDefinition> fieldDefs = new HashMap<>();
-
-        // To store the id of the polymorphic configuration instance.
-        FieldDefinition polymorphicTypeIdFieldDef = null;
-
-        // Field with @InjectedName.
-        FieldDefinition injectedNameFieldDef = null;
-
-        for (Field schemaField : concat(schemaFields, internalFields, polymorphicFields)) {
-            String fieldName = fieldName(schemaField);
-
-            FieldDefinition fieldDef = addNodeField(classDef, schemaField, fieldName);
-
-            fieldDefs.put(fieldName, fieldDef);
-
-            if (isPolymorphicId(schemaField)) {
-                polymorphicTypeIdFieldDef = fieldDef;
-            } else if (isInjectedName(schemaField)) {
-                injectedNameFieldDef = fieldDef;
-            }
-        }
-
-        // org.apache.ignite.internal.configuration.tree.InnerNode#schemaType
-        addNodeSchemaTypeMethod(classDef, schemaClass, polymorphicExtensions, polymorphicTypeIdFieldDef);
-
-        FieldDefinition internalSchemaTypesFieldDef = null;
-
-        if (!internalExtensions.isEmpty()) {
-            internalSchemaTypesFieldDef = classDef.declareField(
-                    of(PRIVATE, FINAL),
-                    "_" + INTERNAL_SCHEMA_TYPES_MTD.getName(),
-                    Class[].class
-            );
-        }
-
-        // Constructor.
-        addNodeConstructor(
-                classDef,
-                specFields,
-                fieldDefs,
-                schemaFields,
-                internalFields,
-                polymorphicFields,
-                internalExtensions,
-                internalSchemaTypesFieldDef
-        );
-
-        // Add view method for internal id.
-        if (internalIdField != null) {
-            addNodeInternalIdMethod(classDef, internalIdField);
-        }
-
-        // VIEW and CHANGE methods.
-        for (Field schemaField : concat(schemaFields, internalFields)) {
-            String fieldName = schemaField.getName();
-
-            FieldDefinition fieldDef = fieldDefs.get(fieldName);
-
-            addNodeViewMethod(
-                    classDef,
-                    schemaField,
-                    viewMtd -> getThisFieldCode(viewMtd, fieldDef),
-                    null
-            );
-
-            // Read only.
-            if (isPolymorphicId(schemaField) || isInjectedName(schemaField)) {
-                continue;
-            }
-
-            // Add change methods.
-            MethodDefinition changeMtd0 = addNodeChangeMethod(
-                    classDef,
-                    schemaField,
-                    changeMtd -> getThisFieldCode(changeMtd, fieldDef),
-                    (changeMtd, newValue) -> setThisFieldCode(changeMtd, newValue, fieldDef),
-                    null
-            );
-
-            addNodeChangeBridgeMethod(classDef, changeClassName(schemaField.getDeclaringClass()), changeMtd0);
-        }
-
-        Map<Class<?>, List<Field>> polymorphicFieldsByExtension = Map.of();
-
-        MethodDefinition changePolymorphicTypeIdMtd = null;
-
-        if (!polymorphicExtensions.isEmpty()) {
-            assert polymorphicTypeIdFieldDef != null : schemaClass.getName();
-
-            addNodeSpecificNodeMethod(classDef, polymorphicExtensions, polymorphicTypeIdFieldDef);
-
-            changePolymorphicTypeIdMtd = addNodeChangePolymorphicTypeIdMethod(
-                    classDef,
-                    fieldDefs,
-                    polymorphicExtensions,
-                    polymorphicFields,
-                    polymorphicTypeIdFieldDef
-            );
-
-            addNodeConvertMethods(classDef, schemaClass, polymorphicExtensions, changePolymorphicTypeIdMtd);
-
-            polymorphicFieldsByExtension = new LinkedHashMap<>();
-
-            for (Class<?> polymorphicExtension : polymorphicExtensions) {
-                polymorphicFieldsByExtension.put(
-                        polymorphicExtension,
-                        polymorphicFields.stream()
-                                .filter(f -> polymorphicExtension.equals(f.getDeclaringClass()))
-                                .collect(toList())
-                );
-            }
-        }
-
-        // traverseChildren
-        addNodeTraverseChildrenMethod(
-                classDef,
-                schemaClass,
-                fieldDefs,
-                schemaFields,
-                internalFields,
-                polymorphicFieldsByExtension,
-                polymorphicTypeIdFieldDef
-        );
-
-        // traverseChild
-        addNodeTraverseChildMethod(
-                classDef,
-                fieldDefs,
-                schemaFields,
-                internalFields,
-                polymorphicFieldsByExtension,
-                polymorphicTypeIdFieldDef
-        );
-
-        // construct
-        addNodeConstructMethod(
-                classDef,
-                fieldDefs,
-                schemaFields,
-                internalFields,
-                polymorphicFieldsByExtension,
-                polymorphicTypeIdFieldDef,
-                changePolymorphicTypeIdMtd
-        );
+    BytecodeExpression newOrCopyNodeField(Field schemaField, BytecodeExpression getFieldCode) {
+        ParameterizedType nodeType = typeFromJavaClassName(schemasInfo.get(schemaField.getType()).nodeClassName);
 
-        // constructDefault
-        addNodeConstructDefaultMethod(
-                schemaClass,
-                classDef,
-                specFields,
-                fieldDefs,
-                schemaFields,
-                internalFields,
-                polymorphicFieldsByExtension,
-                polymorphicTypeIdFieldDef
+        // this.field == null ? new ValueNode() : (ValueNode)this.field.copy();
+        return inlineIf(
+                isNull(getFieldCode),
+                newInstance(nodeType),
+                copyNodeField(schemaField, getFieldCode)
         );
+    }
 
-        if (injectedNameFieldDef != null) {
-            addInjectedNameFieldMethods(classDef, injectedNameFieldDef);
-        }
-
-        if (polymorphicTypeIdFieldDef != null) {
-            addIsPolymorphicMethod(classDef);
-        }
-
-        if (internalSchemaTypesFieldDef != null) {
-            addInternalSchemaTypesMethod(classDef, internalSchemaTypesFieldDef);
-        }
-
-        if (schemaClass.getSuperclass().isAnnotationPresent(AbstractConfiguration.class)) {
-            addIsExtendAbstractConfigurationMethod(classDef);
-        }
+    /**
+     * Copies field into itself. Code like: {@code (ValueNode)this.field.copy();}.
+     *
+     * @param schemaField  Configuration schema class field.
+     * @param getFieldCode Bytecode of getting the field, for example: {@code this.field} or {@code this.field.field};
+     * @return Bytecode expression.
+     */
+    BytecodeExpression copyNodeField(Field schemaField, BytecodeExpression getFieldCode) {
+        ParameterizedType nodeType = isNamedConfigValue(schemaField)
+                ? type(NamedListNode.class) : typeFromJavaClassName(schemasInfo.get(schemaField.getType()).nodeClassName);
 
-        return classDef;
+        // (ValueNode)this.field.copy();
+        return getFieldCode.invoke(COPY).cast(nodeType);
     }
 
     /**
-     * Add {@link InnerNode#schemaType} method implementation to the class.
+     * Creates {@code *Node::new} lambda expression with {@link Supplier} type.
      *
-     * @param classDef                  Class definition.
-     * @param schemaClass               Configuration schema class.
-     * @param polymorphicExtensions     Polymorphic extensions of the configuration schema.
-     * @param polymorphicTypeIdFieldDef Identification field for the polymorphic configuration instance.
+     * @param nodeClassName Name of the {@code *Node} class.
+     * @return InvokeDynamic bytecode expression.
      */
-    private static void addNodeSchemaTypeMethod(
-            ClassDefinition classDef,
-            Class<?> schemaClass,
-            Set<Class<?>> polymorphicExtensions,
-            @Nullable FieldDefinition polymorphicTypeIdFieldDef
-    ) {
-        MethodDefinition schemaTypeMtd = classDef.declareMethod(
-                of(PUBLIC),
-                "schemaType",
-                type(Class.class)
+    @NotNull
+    private static BytecodeExpression newNamedListElementLambda(String nodeClassName) {
+        return invokeDynamic(
+                LAMBDA_METAFACTORY,
+                asList(
+                        getMethodType(getType(Object.class)),
+                        new Handle(
+                                H_NEWINVOKESPECIAL,
+                                internalName(nodeClassName),
+                                "<init>",
+                                getMethodDescriptor(Type.VOID_TYPE),
+                                false
+                        ),
+                        getMethodType(typeFromJavaClassName(nodeClassName).getAsmType())
+                ),
+                "get",
+                methodType(Supplier.class)
         );
-
-        BytecodeBlock mtdBody = schemaTypeMtd.getBody();
-
-        if (polymorphicExtensions.isEmpty()) {
-            mtdBody.append(constantClass(schemaClass)).retObject();
-        } else {
-            assert polymorphicTypeIdFieldDef != null : classDef.getName();
-
-            StringSwitchBuilder switchBuilderTypeId = typeIdSwitchBuilder(schemaTypeMtd, polymorphicTypeIdFieldDef);
-
-            for (Class<?> polymorphicExtension : polymorphicExtensions) {
-                switchBuilderTypeId.addCase(
-                        polymorphicInstanceId(polymorphicExtension),
-                        constantClass(polymorphicExtension).ret()
-                );
-            }
-
-            mtdBody.append(switchBuilderTypeId.build());
-        }
     }
 
     /**
-     * Declares field that corresponds to configuration value. Depending on the schema, 5 options possible:
-     * <ul>
-     *     <li>
-     *         {@code @Value public type fieldName}<br/>becomes<br/>
-     *         {@code public BoxedType fieldName}
-     *     </li>
-     *     <li>
-     *         {@code @ConfigValue public MyConfigurationSchema fieldName}<br/>becomes<br/>
-     *         {@code public MyNode fieldName}
-     *     </li>
-     *     <li>
-     *         {@code @NamedConfigValue public type fieldName}<br/>becomes<br/>
-     *         {@code public NamedListNode fieldName}
-     *     </li>
-     *     <li>
-     *         {@code @PolymorphicId public String fieldName}<br/>becomes<br/>
-     *         {@code public String fieldName}
-     *     </li>
-     *     <li>
-     *         {@code @InjectedName public String fieldName}<br/>becomes<br/>
-     *         {@code public String fieldName}
-     *     </li>
-     * </ul>
+     * Replaces first letter in string with its upper-cased variant.
      *
-     * @param classDef    Node class definition.
-     * @param schemaField Configuration Schema class field.
-     * @param fieldName   Field name.
-     * @return Declared field definition.
-     * @throws IllegalArgumentException If an unsupported {@code schemaField} was passed.
+     * @param name Some string.
+     * @return Capitalized version of passed string.
      */
-    private FieldDefinition addNodeField(ClassDefinition classDef, Field schemaField, String fieldName) {
-        Class<?> schemaFieldClass = schemaField.getType();
-
-        ParameterizedType nodeFieldType;
-
-        if (isValue(schemaField) || isPolymorphicId(schemaField) || isInjectedName(schemaField)) {
-            nodeFieldType = type(box(schemaFieldClass));
-        } else if (isConfigValue(schemaField)) {
-            nodeFieldType = typeFromJavaClassName(schemasInfo.get(schemaFieldClass).nodeClassName);
-        } else if (isNamedConfigValue(schemaField)) {
-            nodeFieldType = type(NamedListNode.class);
-        } else {
-            throw new IllegalArgumentException("Unsupported field: " + schemaField);
-        }
-
-        return classDef.declareField(of(PUBLIC), fieldName, nodeFieldType);
+    private static String capitalize(String name) {
+        return name.substring(0, 1).toUpperCase() + name.substring(1);
     }
 
     /**
-     * Implements default constructor for the node class. It initializes {@code _spec} field and every other field that represents named
-     * list configuration.
+     * Returns internalized version of class name, replacing dots with slashes.

Review Comment:
   When I read 'internalized', I first think about `String#intern()`, but it's something different. Can this be reworded to avoid confusion?



##########
modules/configuration/src/main/java/org/apache/ignite/internal/configuration/asm/ConfigurationAsmGenerator.java:
##########
@@ -75,257 +50,53 @@
 import static org.objectweb.asm.Type.getType;
 
 import com.facebook.presto.bytecode.BytecodeBlock;
-import com.facebook.presto.bytecode.BytecodeNode;
 import com.facebook.presto.bytecode.ClassDefinition;
 import com.facebook.presto.bytecode.ClassGenerator;
 import com.facebook.presto.bytecode.FieldDefinition;
 import com.facebook.presto.bytecode.MethodDefinition;
 import com.facebook.presto.bytecode.ParameterizedType;
-import com.facebook.presto.bytecode.Variable;
-import com.facebook.presto.bytecode.control.IfStatement;
 import com.facebook.presto.bytecode.expression.BytecodeExpression;
-import java.io.Serializable;
-import java.lang.invoke.LambdaMetafactory;
-import java.lang.invoke.MethodHandle;
-import java.lang.invoke.MethodHandles.Lookup;
-import java.lang.invoke.MethodType;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
-import java.lang.reflect.Method;
 import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
-import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
-import java.util.NoSuchElementException;
-import java.util.Objects;
 import java.util.Queue;
 import java.util.Set;
-import java.util.UUID;
-import java.util.function.BiFunction;
-import java.util.function.Consumer;
-import java.util.function.Function;
 import java.util.function.Supplier;
 import java.util.stream.Stream;
-import org.apache.ignite.configuration.ConfigurationProperty;
-import org.apache.ignite.configuration.ConfigurationTree;
-import org.apache.ignite.configuration.ConfigurationValue;
 import org.apache.ignite.configuration.ConfigurationWrongPolymorphicTypeIdException;
-import org.apache.ignite.configuration.NamedConfigurationTree;
-import org.apache.ignite.configuration.NamedListView;
 import org.apache.ignite.configuration.RootKey;
 import org.apache.ignite.configuration.annotation.AbstractConfiguration;
 import org.apache.ignite.configuration.annotation.Config;
 import org.apache.ignite.configuration.annotation.ConfigurationRoot;
-import org.apache.ignite.configuration.annotation.InjectedName;
 import org.apache.ignite.configuration.annotation.InternalConfiguration;
-import org.apache.ignite.configuration.annotation.Name;
 import org.apache.ignite.configuration.annotation.NamedConfigValue;
 import org.apache.ignite.configuration.annotation.PolymorphicConfig;
 import org.apache.ignite.configuration.annotation.PolymorphicConfigInstance;
 import org.apache.ignite.configuration.annotation.PolymorphicId;
-import org.apache.ignite.internal.configuration.ConfigurationNode;
-import org.apache.ignite.internal.configuration.ConfigurationTreeWrapper;
 import org.apache.ignite.internal.configuration.DynamicConfiguration;
 import org.apache.ignite.internal.configuration.DynamicConfigurationChanger;
-import org.apache.ignite.internal.configuration.DynamicProperty;
-import org.apache.ignite.internal.configuration.NamedListConfiguration;
 import org.apache.ignite.internal.configuration.TypeUtils;
-import org.apache.ignite.internal.configuration.direct.DirectPropertyProxy;
-import org.apache.ignite.internal.configuration.tree.ConfigurationSource;
-import org.apache.ignite.internal.configuration.tree.ConfigurationVisitor;
-import org.apache.ignite.internal.configuration.tree.ConstructableTreeNode;
 import org.apache.ignite.internal.configuration.tree.InnerNode;
 import org.apache.ignite.internal.configuration.tree.NamedListNode;
 import org.apache.ignite.internal.configuration.util.ConfigurationUtil;
-import org.apache.ignite.internal.util.ArrayUtils;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 import org.objectweb.asm.Handle;
-import org.objectweb.asm.Opcodes;
 import org.objectweb.asm.Type;
 
 /**
  * This class is responsible for generating internal implementation classes for configuration schemas. It uses classes from {@code bytecode}
  * module to achieve this goal, like {@link ClassGenerator}, for examples.

Review Comment:
   ```suggestion
    * module to achieve this goal, like {@link ClassGenerator}, for example.
   ```



##########
modules/configuration/src/main/java/org/apache/ignite/internal/configuration/asm/ConfigurationImplAsmGenerator.java:
##########
@@ -0,0 +1,872 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.configuration.asm;
+
+import static com.facebook.presto.bytecode.Access.FINAL;
+import static com.facebook.presto.bytecode.Access.PRIVATE;
+import static com.facebook.presto.bytecode.Access.PUBLIC;
+import static com.facebook.presto.bytecode.Access.STATIC;
+import static com.facebook.presto.bytecode.Access.SYNTHETIC;
+import static com.facebook.presto.bytecode.Parameter.arg;
+import static com.facebook.presto.bytecode.ParameterizedType.type;
+import static com.facebook.presto.bytecode.ParameterizedType.typeFromJavaClassName;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.constantBoolean;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.constantClass;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.constantInt;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.constantString;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.inlineIf;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.invokeDynamic;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.newArray;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.newInstance;
+import static com.facebook.presto.bytecode.expression.BytecodeExpressions.set;
+import static java.util.Arrays.asList;
+import static java.util.Collections.emptyList;
+import static java.util.EnumSet.of;
+import static java.util.function.Function.identity;
+import static java.util.stream.Collectors.toList;
+import static java.util.stream.Collectors.toMap;
+import static org.apache.ignite.internal.configuration.asm.ConfigurationAsmGenerator.fieldName;
+import static org.apache.ignite.internal.configuration.asm.ConfigurationAsmGenerator.getThisFieldCode;
+import static org.apache.ignite.internal.configuration.asm.ConfigurationAsmGenerator.internalName;
+import static org.apache.ignite.internal.configuration.asm.ConfigurationAsmGenerator.setThisFieldCode;
+import static org.apache.ignite.internal.configuration.asm.ConfigurationAsmGenerator.throwException;
+import static org.apache.ignite.internal.configuration.asm.DirectProxyAsmGenerator.newDirectProxyLambda;
+import static org.apache.ignite.internal.configuration.asm.SchemaClassesInfo.configurationClassName;
+import static org.apache.ignite.internal.configuration.asm.SchemaClassesInfo.nodeClassName;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.isConfigValue;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.isInjectedName;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.isInternalId;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.isNamedConfigValue;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.isPolymorphicConfig;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.isPolymorphicConfigInstance;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.isPolymorphicId;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.isValue;
+import static org.apache.ignite.internal.configuration.util.ConfigurationUtil.polymorphicInstanceId;
+import static org.apache.ignite.internal.util.ArrayUtils.nullOrEmpty;
+import static org.apache.ignite.internal.util.CollectionUtils.concat;
+import static org.objectweb.asm.Type.getMethodType;
+import static org.objectweb.asm.Type.getType;
+
+import com.facebook.presto.bytecode.BytecodeBlock;
+import com.facebook.presto.bytecode.ClassDefinition;
+import com.facebook.presto.bytecode.FieldDefinition;
+import com.facebook.presto.bytecode.MethodDefinition;
+import com.facebook.presto.bytecode.ParameterizedType;
+import com.facebook.presto.bytecode.Variable;
+import com.facebook.presto.bytecode.expression.BytecodeExpression;
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.BiFunction;
+import org.apache.ignite.configuration.ConfigurationProperty;
+import org.apache.ignite.configuration.ConfigurationTree;
+import org.apache.ignite.configuration.ConfigurationValue;
+import org.apache.ignite.configuration.ConfigurationWrongPolymorphicTypeIdException;
+import org.apache.ignite.configuration.NamedConfigurationTree;
+import org.apache.ignite.configuration.RootKey;
+import org.apache.ignite.internal.configuration.ConfigurationNode;
+import org.apache.ignite.internal.configuration.ConfigurationTreeWrapper;
+import org.apache.ignite.internal.configuration.DynamicConfiguration;
+import org.apache.ignite.internal.configuration.DynamicConfigurationChanger;
+import org.apache.ignite.internal.configuration.DynamicProperty;
+import org.apache.ignite.internal.configuration.NamedListConfiguration;
+import org.apache.ignite.internal.configuration.direct.DirectPropertyProxy;
+import org.apache.ignite.internal.configuration.tree.InnerNode;
+import org.jetbrains.annotations.Nullable;
+import org.objectweb.asm.Handle;
+import org.objectweb.asm.Opcodes;
+
+class ConfigurationImplAsmGenerator extends AbstractAsmGenerator {
+    /** Class definition that extends the {@link DynamicConfiguration}. */
+    private ClassDefinition cfgImplClassDef;
+
+    ConfigurationImplAsmGenerator(
+            ConfigurationAsmGenerator cgen,
+            Class<?> schemaClass,
+            Set<Class<?>> internalExtensions,
+            Set<Class<?>> polymorphicExtensions,
+            List<Field> schemaFields,
+            Collection<Field> internalFields,
+            Collection<Field> polymorphicFields,
+            @Nullable Field internalIdField
+    ) {
+        super(
+                cgen,
+                schemaClass,
+                internalExtensions,
+                polymorphicExtensions,
+                schemaFields,
+                internalFields,
+                polymorphicFields,
+                internalIdField
+        );
+    }
+
+    @Override
+    public List<ClassDefinition> generate() {
+        assert cfgImplClassDef == null;
+
+        List<ClassDefinition> classDefs = new ArrayList<>();
+
+        classDefs.add(createCfgImplClass());
+
+        for (Class<?> polymorphicExtension : polymorphicExtensions) {
+            // Only the fields of a specific instance of a polymorphic configuration.
+            Collection<Field> polymorphicFields = this.polymorphicFields.stream()
+                    .filter(f -> f.getDeclaringClass() == polymorphicExtension)
+                    .collect(toList());
+
+            classDefs.add(createPolymorphicExtensionCfgImplClass(polymorphicExtension, polymorphicFields));
+        }
+
+        return classDefs;
+    }
+
+    /**
+     * Construct a {@link DynamicConfiguration} definition for a configuration schema.
+     *
+     * @return Constructed {@link DynamicConfiguration} definition for the configuration schema.
+     */
+    private ClassDefinition createCfgImplClass() {
+        SchemaClassesInfo schemaClassInfo = cgen.schemaInfo(schemaClass);
+
+        // Configuration impl class definition.
+        cfgImplClassDef = new ClassDefinition(
+                of(PUBLIC, FINAL),
+                internalName(schemaClassInfo.cfgImplClassName),
+                type(DynamicConfiguration.class),
+                cgen.configClassInterfaces(schemaClass, internalExtensions)
+        );
+
+        // Fields.

Review Comment:
   Does this comment relato to just the following line or to the whole block that processes fields? If the former is true, the comment does not seem to have any utility (as the code speaks for itself), how about dropping it? If the latter is true, the comment could be separated from the following line to give a hint that it's not about the line, but about a block.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: notifications-unsubscribe@ignite.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org