ibessonov commented on a change in pull request #5:
URL: https://github.com/apache/ignite-3/pull/5#discussion_r535139224



##########
File path: modules/config-sample/pom.xml
##########
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  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.
+-->
+
+<!--
+    POM file.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>org.apache.ignite</groupId>
+    <artifactId>ignite-configuration-sample</artifactId>
+    <version>3.0-SNAPSHOT</version>
+    <url>http://ignite.apache.org</url>
+
+    <properties>
+        <maven.compiler.source>1.8</maven.compiler.source>
+        <maven.compiler.target>1.8</maven.compiler.target>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>log4j</groupId>
+            <artifactId>log4j</artifactId>
+            <version>1.2.17</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>com.typesafe</groupId>
+            <artifactId>config</artifactId>
+            <version>1.4.1</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.ignite</groupId>
+            <artifactId>ignite-configuration</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>4.13</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.8.1</version>
+                <configuration>
+                    <annotationProcessors>
+                        
<annotationProcessor>org.apache.ignite.configuration.processor.internal.Processor</annotationProcessor>

Review comment:
       Is there a chance of putting this into meta-inf of processor module?

##########
File path: modules/config-sample/pom.xml
##########
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  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.
+-->
+
+<!--
+    POM file.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>org.apache.ignite</groupId>
+    <artifactId>ignite-configuration-sample</artifactId>
+    <version>3.0-SNAPSHOT</version>
+    <url>http://ignite.apache.org</url>
+
+    <properties>
+        <maven.compiler.source>1.8</maven.compiler.source>
+        <maven.compiler.target>1.8</maven.compiler.target>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>log4j</groupId>
+            <artifactId>log4j</artifactId>
+            <version>1.2.17</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>com.typesafe</groupId>

Review comment:
       It would be cool to sort dependencies, test dependencies will be clearly 
separated then.

##########
File path: 
modules/configuration-annotation-processor/src/main/java/org/apache/ignite/configuration/processor/internal/Processor.java
##########
@@ -0,0 +1,692 @@
+/*
+ * 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.configuration.processor.internal;
+
+import java.io.IOException;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.Filer;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.annotation.processing.RoundEnvironment;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.util.Elements;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.FieldSpec;
+import com.squareup.javapoet.JavaFile;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.ParameterizedTypeName;
+import com.squareup.javapoet.TypeName;
+import com.squareup.javapoet.TypeSpec;
+import com.squareup.javapoet.WildcardTypeName;
+import org.apache.ignite.configuration.internal.Configurator;
+import org.apache.ignite.configuration.internal.DynamicConfiguration;
+import org.apache.ignite.configuration.internal.NamedListConfiguration;
+import org.apache.ignite.configuration.internal.annotation.Config;
+import org.apache.ignite.configuration.internal.annotation.ConfigValue;
+import org.apache.ignite.configuration.internal.annotation.NamedConfigValue;
+import org.apache.ignite.configuration.internal.annotation.Value;
+import org.apache.ignite.configuration.internal.property.DynamicProperty;
+import org.apache.ignite.configuration.internal.selector.BaseSelectors;
+import org.apache.ignite.configuration.internal.selector.Selector;
+import org.apache.ignite.configuration.internal.validation.MemberKey;
+import 
org.apache.ignite.configuration.processor.internal.pojo.ChangeClassGenerator;
+import 
org.apache.ignite.configuration.processor.internal.pojo.InitClassGenerator;
+import 
org.apache.ignite.configuration.processor.internal.pojo.ViewClassGenerator;
+import 
org.apache.ignite.configuration.processor.internal.validation.ValidationGenerator;
+
+import static javax.lang.model.element.Modifier.FINAL;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.PUBLIC;
+import static javax.lang.model.element.Modifier.STATIC;
+
+/**
+ * Annotation processor that produces configuration classes.
+ */
+public class Processor extends AbstractProcessor {
+    /** Generator of VIEW classes. */
+    private ViewClassGenerator viewClassGenerator;
+
+    /** Generator of INIT classes. */
+    private InitClassGenerator initClassGenerator;
+
+    /** Generator of CHANGE classes. */
+    private ChangeClassGenerator changeClassGenerator;
+
+    /** Class file writer. */
+    private Filer filer;
+
+    /** {@inheritDoc} */
+    @Override public synchronized void init(ProcessingEnvironment 
processingEnv) {
+        super.init(processingEnv);
+        filer = processingEnv.getFiler();
+        viewClassGenerator = new ViewClassGenerator(processingEnv);
+        initClassGenerator = new InitClassGenerator(processingEnv);
+        changeClassGenerator = new ChangeClassGenerator(processingEnv);
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean process(Set<? extends TypeElement> annotations, 
RoundEnvironment roundEnvironment) {
+        final Elements elementUtils = processingEnv.getElementUtils();
+
+        Map<TypeName, ConfigurationDescription> props = new HashMap<>();
+
+        List<ConfigurationDescription> roots = new ArrayList<>();
+
+        String packageForUtil = "";
+
+        final Set<? extends Element> annotatedConfigs = 
roundEnvironment.getElementsAnnotatedWith(Config.class);
+
+        if (annotatedConfigs.isEmpty())
+            return false;
+
+        for (Element element : annotatedConfigs) {
+            if (element.getKind() != ElementKind.CLASS) {
+                continue;
+            }
+            TypeElement clazz = (TypeElement) element;
+
+            final PackageElement elementPackage = 
elementUtils.getPackageOf(clazz);
+            final String packageName = 
elementPackage.getQualifiedName().toString();
+
+            final List<VariableElement> fields
+                = clazz.getEnclosedElements().stream()

Review comment:
       Another weird formatting. I get that we don't have strict rules yet 
(probably), but this doesn't look like any other Ignite code.

##########
File path: 
modules/configuration-annotation-processor/src/main/java/org/apache/ignite/configuration/processor/internal/Processor.java
##########
@@ -0,0 +1,692 @@
+/*
+ * 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.configuration.processor.internal;
+
+import java.io.IOException;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.Filer;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.annotation.processing.RoundEnvironment;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.util.Elements;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.FieldSpec;
+import com.squareup.javapoet.JavaFile;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.ParameterizedTypeName;
+import com.squareup.javapoet.TypeName;
+import com.squareup.javapoet.TypeSpec;
+import com.squareup.javapoet.WildcardTypeName;
+import org.apache.ignite.configuration.internal.Configurator;
+import org.apache.ignite.configuration.internal.DynamicConfiguration;
+import org.apache.ignite.configuration.internal.NamedListConfiguration;
+import org.apache.ignite.configuration.internal.annotation.Config;
+import org.apache.ignite.configuration.internal.annotation.ConfigValue;
+import org.apache.ignite.configuration.internal.annotation.NamedConfigValue;
+import org.apache.ignite.configuration.internal.annotation.Value;
+import org.apache.ignite.configuration.internal.property.DynamicProperty;
+import org.apache.ignite.configuration.internal.selector.BaseSelectors;
+import org.apache.ignite.configuration.internal.selector.Selector;
+import org.apache.ignite.configuration.internal.validation.MemberKey;
+import 
org.apache.ignite.configuration.processor.internal.pojo.ChangeClassGenerator;
+import 
org.apache.ignite.configuration.processor.internal.pojo.InitClassGenerator;
+import 
org.apache.ignite.configuration.processor.internal.pojo.ViewClassGenerator;
+import 
org.apache.ignite.configuration.processor.internal.validation.ValidationGenerator;
+
+import static javax.lang.model.element.Modifier.FINAL;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.PUBLIC;
+import static javax.lang.model.element.Modifier.STATIC;
+
+/**
+ * Annotation processor that produces configuration classes.
+ */
+public class Processor extends AbstractProcessor {
+    /** Generator of VIEW classes. */
+    private ViewClassGenerator viewClassGenerator;
+
+    /** Generator of INIT classes. */
+    private InitClassGenerator initClassGenerator;
+
+    /** Generator of CHANGE classes. */
+    private ChangeClassGenerator changeClassGenerator;
+
+    /** Class file writer. */
+    private Filer filer;
+
+    /** {@inheritDoc} */
+    @Override public synchronized void init(ProcessingEnvironment 
processingEnv) {
+        super.init(processingEnv);
+        filer = processingEnv.getFiler();
+        viewClassGenerator = new ViewClassGenerator(processingEnv);
+        initClassGenerator = new InitClassGenerator(processingEnv);
+        changeClassGenerator = new ChangeClassGenerator(processingEnv);
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean process(Set<? extends TypeElement> annotations, 
RoundEnvironment roundEnvironment) {
+        final Elements elementUtils = processingEnv.getElementUtils();
+
+        Map<TypeName, ConfigurationDescription> props = new HashMap<>();
+
+        List<ConfigurationDescription> roots = new ArrayList<>();
+
+        String packageForUtil = "";
+
+        final Set<? extends Element> annotatedConfigs = 
roundEnvironment.getElementsAnnotatedWith(Config.class);
+
+        if (annotatedConfigs.isEmpty())
+            return false;
+
+        for (Element element : annotatedConfigs) {
+            if (element.getKind() != ElementKind.CLASS) {
+                continue;
+            }
+            TypeElement clazz = (TypeElement) element;
+
+            final PackageElement elementPackage = 
elementUtils.getPackageOf(clazz);
+            final String packageName = 
elementPackage.getQualifiedName().toString();
+
+            final List<VariableElement> fields
+                = clazz.getEnclosedElements().stream()
+                .filter(el -> el.getKind() == ElementKind.FIELD)
+                .map(el -> (VariableElement) el)

Review comment:
       "VariableElement.class::cast" - will this work? I'd like it better.

##########
File path: 
modules/configuration/src/main/java/org/apache/ignite/configuration/internal/Configurator.java
##########
@@ -0,0 +1,105 @@
+/*
+ * 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.configuration.internal;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import org.apache.ignite.configuration.internal.property.DynamicProperty;
+import org.apache.ignite.configuration.internal.property.Modifier;
+import org.apache.ignite.configuration.internal.property.PropertyListener;
+import org.apache.ignite.configuration.internal.selector.Selector;
+import org.apache.ignite.configuration.internal.validation.FieldValidator;
+import org.apache.ignite.configuration.internal.validation.MemberKey;
+
+public class Configurator<T extends DynamicConfiguration<?, ?, ?>> {
+
+    private final ConfigurationStorage storage;
+
+    private final T root;
+
+    private final Map<MemberKey, List<FieldValidator<? extends Serializable, ? 
extends DynamicConfiguration<?, ?, ?>>>> fieldValidators = new HashMap<>();
+
+    public Configurator(ConfigurationStorage storage, 
Function<Configurator<T>, T> rootBuilder) {
+        this.storage = storage;
+        this.root = rootBuilder.apply(this);
+        this.init();
+    }
+
+    private void init() {
+        List<DynamicProperty> props = new ArrayList<>();
+
+        props.forEach(property -> {

Review comment:
       "props" is empty, right?

##########
File path: 
modules/configuration/src/main/java/org/apache/ignite/configuration/internal/ConfigurationStorage.java
##########
@@ -0,0 +1,54 @@
+/*
+ * 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.configuration.internal;
+
+import java.io.Serializable;
+import java.util.function.Consumer;
+
+/**
+ * Storage interface for configuration.
+ */
+public interface ConfigurationStorage {
+    /**
+     * Save configuration property.
+     *
+     * @param propertyName Fully qualified name of the property.
+     * @param object Object, that represents the value of the property.
+     * @param <T> Type of the property.
+     */
+    <T extends Serializable> void save(String propertyName, T object);

Review comment:
       No exceptions in signature

##########
File path: 
modules/config-sample/src/main/java/org/apache/ignite/configuration/internal/AutoAdjustConfigurationSchema.java
##########
@@ -0,0 +1,43 @@
+/*
+ * 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.configuration.internal;

Review comment:
       This is from module with samples. It will be removed, right?

##########
File path: modules/configuration-annotation-processor/pom.xml
##########
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  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.
+-->
+
+<!--
+    POM file.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>org.apache.ignite</groupId>
+    <artifactId>ignite-configuration-annotation-processor</artifactId>
+    <version>3.0-SNAPSHOT</version>
+    <url>http://ignite.apache.org</url>
+
+    <properties>
+        <maven.compiler.source>1.8</maven.compiler.source>

Review comment:
       Please use configuration of maven compiler plugin instead of these 
obsolete properties. Or at least discuss this part with somebody :)

##########
File path: modules/configuration-annotation-processor/pom.xml
##########
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+  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.
+-->
+
+<!--
+    POM file.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>org.apache.ignite</groupId>
+    <artifactId>ignite-configuration-annotation-processor</artifactId>
+    <version>3.0-SNAPSHOT</version>
+    <url>http://ignite.apache.org</url>
+
+    <properties>
+        <maven.compiler.source>1.8</maven.compiler.source>
+        <maven.compiler.target>1.8</maven.compiler.target>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>log4j</groupId>
+            <artifactId>log4j</artifactId>
+            <version>1.2.17</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>com.squareup</groupId>
+            <artifactId>javapoet</artifactId>
+            <version>1.13.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.ignite</groupId>
+            <artifactId>ignite-configuration</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.mockito</groupId>
+            <artifactId>mockito-core</artifactId>
+            <version>3.4.6</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>com.google.testing.compile</groupId>
+            <artifactId>compile-testing</artifactId>
+            <version>0.19</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.junit.jupiter</groupId>
+            <artifactId>junit-jupiter-engine</artifactId>
+            <version>5.6.2</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>fr.inria.gforge.spoon</groupId>
+            <artifactId>spoon-core</artifactId>

Review comment:
       Spoon is available either under the terms of the MIT License (see 
LICENSE-MIT.txt) of the Cecill-C License (see LICENSE-CECILL-C.txt). You as the 
user are entitled to choose the terms under which to adopt Spoon.
   
   I'm not a specialist in this field. Can we use this library?

##########
File path: 
modules/configuration-annotation-processor/src/main/java/org/apache/ignite/configuration/processor/internal/ConfigurationDescription.java
##########
@@ -0,0 +1,42 @@
+/*
+ * 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.configuration.processor.internal;
+
+import java.util.ArrayList;
+import java.util.List;
+import com.squareup.javapoet.TypeName;
+
+/**
+ * Configuration and all it's inner fields.
+ */
+public class ConfigurationDescription extends ConfigurationElement {
+    /** Inner configuration fields. */
+    private List<ConfigurationElement> fields = new ArrayList<>();
+
+    /** Constructor. */
+    public ConfigurationDescription(TypeName type, String name, TypeName view, 
TypeName init, TypeName change) {
+        super(type, name, view, init, change);
+    }
+
+    /**
+     * Get configuration fields.
+     */
+    public List<ConfigurationElement> getFields() {

Review comment:
       How is it different from public final field, like in super class?

##########
File path: 
modules/configuration-annotation-processor/src/main/java/org/apache/ignite/configuration/processor/internal/ConfigurationNode.java
##########
@@ -0,0 +1,53 @@
+/*
+ * 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.configuration.processor.internal;
+
+import com.squareup.javapoet.TypeName;
+
+/**
+ * Configuration element with a reference to it's parent and with an original 
name.

Review comment:
       Typo in "its"

##########
File path: 
modules/configuration-annotation-processor/src/main/java/org/apache/ignite/configuration/processor/internal/Utils.java
##########
@@ -0,0 +1,204 @@
+/*
+ * 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.configuration.processor.internal;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.VariableElement;
+
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.FieldSpec;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.ParameterizedTypeName;
+import com.squareup.javapoet.TypeName;
+import org.apache.ignite.configuration.internal.DynamicConfiguration;
+import org.apache.ignite.configuration.internal.NamedListConfiguration;
+
+/**
+ * Annotation processing utilities.
+ */
+public class Utils {
+    /** Private constructor. */
+    private Utils() {
+    }
+
+    /**
+     * Create constructor for
+     *
+     * @param fieldSpecs List of fields.
+     * @return Constructor method.
+     */
+    public static MethodSpec createConstructor(List<FieldSpec> fieldSpecs) {
+        final MethodSpec.Builder builder = MethodSpec.constructorBuilder();
+        fieldSpecs.forEach(field -> {
+            builder.addParameter(field.type, field.name);
+            builder.addStatement("this.$L = $L", field.name, field.name);
+        });
+        return builder.build();
+    }
+
+    /**
+     * Create getters for fields.
+     *
+     * @param fieldSpecs List of fields.
+     * @return List of getter methods.
+     */
+    public static List<MethodSpec> createGetters(List<FieldSpec> fieldSpecs) {
+        return fieldSpecs.stream().map(field ->
+            MethodSpec.methodBuilder(field.name)
+             .returns(field.type)
+             .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
+             .addStatement("return $L", field.name)
+             .build()).collect(Collectors.toList()
+        );
+    }
+
+    /**
+     * Create builder-style setters.
+     *
+     * @param fieldSpecs List of fields.
+     * @return List of setter methods.
+     */
+    public static List<MethodSpec> createBuildSetters(List<FieldSpec> 
fieldSpecs) {
+        return fieldSpecs.stream().map(field -> {
+            return MethodSpec.methodBuilder("with" + field.name)
+                .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
+                .addStatement("this.$L = $L", field.name, field.name)
+                .build();
+        }).collect(Collectors.toList());
+    }
+
+    /**
+     * Create '{@code new SomeObject(arg1, arg2, ..., argN)}' code block.
+     *
+     * @param type Type of the new object.
+     * @param fieldSpecs List of arguments.
+     * @return New object code block.
+     */
+    public static CodeBlock newObject(TypeName type, List<VariableElement> 
fieldSpecs) {
+        String args = fieldSpecs.stream().map(f -> 
f.getSimpleName().toString()).collect(Collectors.joining(", "));
+        return CodeBlock.builder()
+            .add("new $T($L)", type, args)
+            .build();
+    }
+
+    /**
+     * Get class with parameters, boxing them if necessary.
+     *
+     * @param clz Generic class.
+     * @param types Generic parameters.
+     * @return Parameterized type.
+     */
+    public static ParameterizedTypeName getParameterized(ClassName clz, 
TypeName... types) {
+        types = Arrays.stream(types).map(t -> {
+            if (t.isPrimitive())
+                t = t.box();
+            return t;
+        }).toArray(TypeName[]::new);
+        return ParameterizedTypeName.get(clz, types);
+    }
+
+    /**
+     * Get {@link ClassName} for configuration class.
+     *
+     * @param schemaClassName Configuration schema ClassName.
+     * @return Configuration ClassName.
+     */
+    public static ClassName getConfigurationName(ClassName schemaClassName) {
+        return ClassName.get(
+            schemaClassName.packageName(),
+            schemaClassName.simpleName().replace("Schema", "")

Review comment:
       Wait a minute, but what if I want to have "SqlSchemaConfigurationSchema"?
   Do we have a validation that schema class name ends with Schema?

##########
File path: 
modules/configuration-annotation-processor/src/main/java/org/apache/ignite/configuration/processor/internal/Processor.java
##########
@@ -0,0 +1,692 @@
+/*
+ * 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.configuration.processor.internal;
+
+import java.io.IOException;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.Filer;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.annotation.processing.RoundEnvironment;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.util.Elements;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.FieldSpec;
+import com.squareup.javapoet.JavaFile;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.ParameterizedTypeName;
+import com.squareup.javapoet.TypeName;
+import com.squareup.javapoet.TypeSpec;
+import com.squareup.javapoet.WildcardTypeName;
+import org.apache.ignite.configuration.internal.Configurator;
+import org.apache.ignite.configuration.internal.DynamicConfiguration;
+import org.apache.ignite.configuration.internal.NamedListConfiguration;
+import org.apache.ignite.configuration.internal.annotation.Config;
+import org.apache.ignite.configuration.internal.annotation.ConfigValue;
+import org.apache.ignite.configuration.internal.annotation.NamedConfigValue;
+import org.apache.ignite.configuration.internal.annotation.Value;
+import org.apache.ignite.configuration.internal.property.DynamicProperty;
+import org.apache.ignite.configuration.internal.selector.BaseSelectors;
+import org.apache.ignite.configuration.internal.selector.Selector;
+import org.apache.ignite.configuration.internal.validation.MemberKey;
+import 
org.apache.ignite.configuration.processor.internal.pojo.ChangeClassGenerator;
+import 
org.apache.ignite.configuration.processor.internal.pojo.InitClassGenerator;
+import 
org.apache.ignite.configuration.processor.internal.pojo.ViewClassGenerator;
+import 
org.apache.ignite.configuration.processor.internal.validation.ValidationGenerator;
+
+import static javax.lang.model.element.Modifier.FINAL;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.PUBLIC;
+import static javax.lang.model.element.Modifier.STATIC;
+
+/**
+ * Annotation processor that produces configuration classes.
+ */
+public class Processor extends AbstractProcessor {
+    /** Generator of VIEW classes. */
+    private ViewClassGenerator viewClassGenerator;
+
+    /** Generator of INIT classes. */
+    private InitClassGenerator initClassGenerator;
+
+    /** Generator of CHANGE classes. */
+    private ChangeClassGenerator changeClassGenerator;
+
+    /** Class file writer. */
+    private Filer filer;
+
+    /** {@inheritDoc} */
+    @Override public synchronized void init(ProcessingEnvironment 
processingEnv) {
+        super.init(processingEnv);
+        filer = processingEnv.getFiler();
+        viewClassGenerator = new ViewClassGenerator(processingEnv);
+        initClassGenerator = new InitClassGenerator(processingEnv);
+        changeClassGenerator = new ChangeClassGenerator(processingEnv);
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean process(Set<? extends TypeElement> annotations, 
RoundEnvironment roundEnvironment) {
+        final Elements elementUtils = processingEnv.getElementUtils();
+
+        Map<TypeName, ConfigurationDescription> props = new HashMap<>();
+
+        List<ConfigurationDescription> roots = new ArrayList<>();
+
+        String packageForUtil = "";
+
+        final Set<? extends Element> annotatedConfigs = 
roundEnvironment.getElementsAnnotatedWith(Config.class);
+
+        if (annotatedConfigs.isEmpty())
+            return false;
+
+        for (Element element : annotatedConfigs) {
+            if (element.getKind() != ElementKind.CLASS) {
+                continue;
+            }

Review comment:
       These braces can be removed.

##########
File path: 
modules/configuration-annotation-processor/src/main/java/org/apache/ignite/configuration/processor/internal/Utils.java
##########
@@ -0,0 +1,204 @@
+/*
+ * 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.configuration.processor.internal;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.VariableElement;
+
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.FieldSpec;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.ParameterizedTypeName;
+import com.squareup.javapoet.TypeName;
+import org.apache.ignite.configuration.internal.DynamicConfiguration;
+import org.apache.ignite.configuration.internal.NamedListConfiguration;
+
+/**
+ * Annotation processing utilities.
+ */
+public class Utils {
+    /** Private constructor. */
+    private Utils() {
+    }
+
+    /**
+     * Create constructor for
+     *
+     * @param fieldSpecs List of fields.
+     * @return Constructor method.
+     */
+    public static MethodSpec createConstructor(List<FieldSpec> fieldSpecs) {
+        final MethodSpec.Builder builder = MethodSpec.constructorBuilder();
+        fieldSpecs.forEach(field -> {
+            builder.addParameter(field.type, field.name);
+            builder.addStatement("this.$L = $L", field.name, field.name);
+        });
+        return builder.build();
+    }
+
+    /**
+     * Create getters for fields.
+     *
+     * @param fieldSpecs List of fields.
+     * @return List of getter methods.
+     */
+    public static List<MethodSpec> createGetters(List<FieldSpec> fieldSpecs) {
+        return fieldSpecs.stream().map(field ->
+            MethodSpec.methodBuilder(field.name)
+             .returns(field.type)
+             .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
+             .addStatement("return $L", field.name)
+             .build()).collect(Collectors.toList()
+        );
+    }
+
+    /**
+     * Create builder-style setters.
+     *
+     * @param fieldSpecs List of fields.
+     * @return List of setter methods.
+     */
+    public static List<MethodSpec> createBuildSetters(List<FieldSpec> 
fieldSpecs) {
+        return fieldSpecs.stream().map(field -> {
+            return MethodSpec.methodBuilder("with" + field.name)
+                .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
+                .addStatement("this.$L = $L", field.name, field.name)
+                .build();
+        }).collect(Collectors.toList());
+    }
+
+    /**
+     * Create '{@code new SomeObject(arg1, arg2, ..., argN)}' code block.
+     *
+     * @param type Type of the new object.
+     * @param fieldSpecs List of arguments.
+     * @return New object code block.
+     */
+    public static CodeBlock newObject(TypeName type, List<VariableElement> 
fieldSpecs) {
+        String args = fieldSpecs.stream().map(f -> 
f.getSimpleName().toString()).collect(Collectors.joining(", "));
+        return CodeBlock.builder()
+            .add("new $T($L)", type, args)
+            .build();
+    }
+
+    /**
+     * Get class with parameters, boxing them if necessary.
+     *
+     * @param clz Generic class.
+     * @param types Generic parameters.
+     * @return Parameterized type.
+     */
+    public static ParameterizedTypeName getParameterized(ClassName clz, 
TypeName... types) {
+        types = Arrays.stream(types).map(t -> {
+            if (t.isPrimitive())
+                t = t.box();
+            return t;
+        }).toArray(TypeName[]::new);
+        return ParameterizedTypeName.get(clz, types);
+    }
+
+    /**
+     * Get {@link ClassName} for configuration class.
+     *
+     * @param schemaClassName Configuration schema ClassName.
+     * @return Configuration ClassName.
+     */
+    public static ClassName getConfigurationName(ClassName schemaClassName) {
+        return ClassName.get(
+            schemaClassName.packageName(),
+            schemaClassName.simpleName().replace("Schema", "")
+        );
+    }
+
+    /**
+     * Get {@link ClassName} for configuration VIEW object class.
+     *
+     * @param schemaClassName Configuration schema ClassName.
+     * @return Configuration VIEW object ClassName.
+     */
+    public static ClassName getViewName(ClassName schemaClassName) {
+        return ClassName.get(
+            schemaClassName.packageName(),
+            schemaClassName.simpleName().replace("ConfigurationSchema", "")

Review comment:
       Do we have validation for this substring?

##########
File path: 
modules/configuration-annotation-processor/src/main/java/org/apache/ignite/configuration/processor/internal/Processor.java
##########
@@ -0,0 +1,692 @@
+/*
+ * 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.configuration.processor.internal;
+
+import java.io.IOException;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.Filer;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.annotation.processing.RoundEnvironment;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.util.Elements;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.FieldSpec;
+import com.squareup.javapoet.JavaFile;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.ParameterizedTypeName;
+import com.squareup.javapoet.TypeName;
+import com.squareup.javapoet.TypeSpec;
+import com.squareup.javapoet.WildcardTypeName;
+import org.apache.ignite.configuration.internal.Configurator;
+import org.apache.ignite.configuration.internal.DynamicConfiguration;
+import org.apache.ignite.configuration.internal.NamedListConfiguration;
+import org.apache.ignite.configuration.internal.annotation.Config;
+import org.apache.ignite.configuration.internal.annotation.ConfigValue;
+import org.apache.ignite.configuration.internal.annotation.NamedConfigValue;
+import org.apache.ignite.configuration.internal.annotation.Value;
+import org.apache.ignite.configuration.internal.property.DynamicProperty;
+import org.apache.ignite.configuration.internal.selector.BaseSelectors;
+import org.apache.ignite.configuration.internal.selector.Selector;
+import org.apache.ignite.configuration.internal.validation.MemberKey;
+import 
org.apache.ignite.configuration.processor.internal.pojo.ChangeClassGenerator;
+import 
org.apache.ignite.configuration.processor.internal.pojo.InitClassGenerator;
+import 
org.apache.ignite.configuration.processor.internal.pojo.ViewClassGenerator;
+import 
org.apache.ignite.configuration.processor.internal.validation.ValidationGenerator;
+
+import static javax.lang.model.element.Modifier.FINAL;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.PUBLIC;
+import static javax.lang.model.element.Modifier.STATIC;
+
+/**
+ * Annotation processor that produces configuration classes.
+ */
+public class Processor extends AbstractProcessor {
+    /** Generator of VIEW classes. */
+    private ViewClassGenerator viewClassGenerator;
+
+    /** Generator of INIT classes. */
+    private InitClassGenerator initClassGenerator;
+
+    /** Generator of CHANGE classes. */
+    private ChangeClassGenerator changeClassGenerator;
+
+    /** Class file writer. */
+    private Filer filer;
+
+    /** {@inheritDoc} */
+    @Override public synchronized void init(ProcessingEnvironment 
processingEnv) {
+        super.init(processingEnv);
+        filer = processingEnv.getFiler();

Review comment:
       You can add empty line here.

##########
File path: 
modules/configuration-annotation-processor/src/main/java/org/apache/ignite/configuration/processor/internal/Utils.java
##########
@@ -0,0 +1,204 @@
+/*
+ * 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.configuration.processor.internal;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.VariableElement;
+
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.FieldSpec;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.ParameterizedTypeName;
+import com.squareup.javapoet.TypeName;
+import org.apache.ignite.configuration.internal.DynamicConfiguration;
+import org.apache.ignite.configuration.internal.NamedListConfiguration;
+
+/**
+ * Annotation processing utilities.
+ */
+public class Utils {
+    /** Private constructor. */
+    private Utils() {
+    }
+
+    /**
+     * Create constructor for
+     *
+     * @param fieldSpecs List of fields.
+     * @return Constructor method.
+     */
+    public static MethodSpec createConstructor(List<FieldSpec> fieldSpecs) {
+        final MethodSpec.Builder builder = MethodSpec.constructorBuilder();
+        fieldSpecs.forEach(field -> {
+            builder.addParameter(field.type, field.name);
+            builder.addStatement("this.$L = $L", field.name, field.name);
+        });
+        return builder.build();
+    }
+
+    /**
+     * Create getters for fields.
+     *
+     * @param fieldSpecs List of fields.
+     * @return List of getter methods.
+     */
+    public static List<MethodSpec> createGetters(List<FieldSpec> fieldSpecs) {
+        return fieldSpecs.stream().map(field ->
+            MethodSpec.methodBuilder(field.name)
+             .returns(field.type)

Review comment:
       Padding with a single space, really?

##########
File path: 
modules/configuration-annotation-processor/src/main/java/org/apache/ignite/configuration/processor/internal/Processor.java
##########
@@ -0,0 +1,692 @@
+/*
+ * 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.configuration.processor.internal;
+
+import java.io.IOException;
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.MethodType;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.IntStream;
+import javax.annotation.processing.AbstractProcessor;
+import javax.annotation.processing.Filer;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.annotation.processing.RoundEnvironment;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.PackageElement;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.util.Elements;
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.FieldSpec;
+import com.squareup.javapoet.JavaFile;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.ParameterizedTypeName;
+import com.squareup.javapoet.TypeName;
+import com.squareup.javapoet.TypeSpec;
+import com.squareup.javapoet.WildcardTypeName;
+import org.apache.ignite.configuration.internal.Configurator;
+import org.apache.ignite.configuration.internal.DynamicConfiguration;
+import org.apache.ignite.configuration.internal.NamedListConfiguration;
+import org.apache.ignite.configuration.internal.annotation.Config;
+import org.apache.ignite.configuration.internal.annotation.ConfigValue;
+import org.apache.ignite.configuration.internal.annotation.NamedConfigValue;
+import org.apache.ignite.configuration.internal.annotation.Value;
+import org.apache.ignite.configuration.internal.property.DynamicProperty;
+import org.apache.ignite.configuration.internal.selector.BaseSelectors;
+import org.apache.ignite.configuration.internal.selector.Selector;
+import org.apache.ignite.configuration.internal.validation.MemberKey;
+import 
org.apache.ignite.configuration.processor.internal.pojo.ChangeClassGenerator;
+import 
org.apache.ignite.configuration.processor.internal.pojo.InitClassGenerator;
+import 
org.apache.ignite.configuration.processor.internal.pojo.ViewClassGenerator;
+import 
org.apache.ignite.configuration.processor.internal.validation.ValidationGenerator;
+
+import static javax.lang.model.element.Modifier.FINAL;
+import static javax.lang.model.element.Modifier.PRIVATE;
+import static javax.lang.model.element.Modifier.PUBLIC;
+import static javax.lang.model.element.Modifier.STATIC;
+
+/**
+ * Annotation processor that produces configuration classes.
+ */
+public class Processor extends AbstractProcessor {
+    /** Generator of VIEW classes. */
+    private ViewClassGenerator viewClassGenerator;
+
+    /** Generator of INIT classes. */
+    private InitClassGenerator initClassGenerator;
+
+    /** Generator of CHANGE classes. */
+    private ChangeClassGenerator changeClassGenerator;
+
+    /** Class file writer. */
+    private Filer filer;
+
+    /** {@inheritDoc} */
+    @Override public synchronized void init(ProcessingEnvironment 
processingEnv) {
+        super.init(processingEnv);
+        filer = processingEnv.getFiler();
+        viewClassGenerator = new ViewClassGenerator(processingEnv);
+        initClassGenerator = new InitClassGenerator(processingEnv);
+        changeClassGenerator = new ChangeClassGenerator(processingEnv);
+    }
+
+    /** {@inheritDoc} */
+    @Override public boolean process(Set<? extends TypeElement> annotations, 
RoundEnvironment roundEnvironment) {
+        final Elements elementUtils = processingEnv.getElementUtils();
+
+        Map<TypeName, ConfigurationDescription> props = new HashMap<>();
+
+        List<ConfigurationDescription> roots = new ArrayList<>();
+
+        String packageForUtil = "";
+
+        final Set<? extends Element> annotatedConfigs = 
roundEnvironment.getElementsAnnotatedWith(Config.class);
+
+        if (annotatedConfigs.isEmpty())
+            return false;
+
+        for (Element element : annotatedConfigs) {
+            if (element.getKind() != ElementKind.CLASS) {
+                continue;
+            }
+            TypeElement clazz = (TypeElement) element;
+
+            final PackageElement elementPackage = 
elementUtils.getPackageOf(clazz);
+            final String packageName = 
elementPackage.getQualifiedName().toString();
+
+            final List<VariableElement> fields
+                = clazz.getEnclosedElements().stream()
+                .filter(el -> el.getKind() == ElementKind.FIELD)
+                .map(el -> (VariableElement) el)
+                .collect(Collectors.toList());
+
+            final Config clazzConfigAnnotation = 
clazz.getAnnotation(Config.class);
+
+            final String configName = clazzConfigAnnotation.value();
+            final boolean isRoot = clazzConfigAnnotation.root();
+            final ClassName schemaClassName = ClassName.get(packageName, 
clazz.getSimpleName().toString());
+            final ClassName configClass = 
Utils.getConfigurationName(schemaClassName);
+
+            ConfigurationDescription configDesc = new 
ConfigurationDescription(configClass, configName, 
Utils.getViewName(schemaClassName), Utils.getInitName(schemaClassName), 
Utils.getChangeName(schemaClassName));
+
+            if (isRoot) {
+                roots.add(configDesc);
+                packageForUtil = packageName;
+            }
+
+            TypeSpec.Builder configurationClassBuilder = TypeSpec
+                .classBuilder(configClass)
+                .addModifiers(PUBLIC, FINAL);
+            TypeName wildcard = WildcardTypeName.subtypeOf(Object.class);
+
+            final ParameterizedTypeName configuratorClassName = 
ParameterizedTypeName.get(
+                ClassName.get(Configurator.class),
+                
WildcardTypeName.subtypeOf(ParameterizedTypeName.get(ClassName.get(DynamicConfiguration.class),
 wildcard, wildcard, wildcard))
+            );
+
+            CodeBlock.Builder constructorBodyBuilder = CodeBlock.builder();
+            CodeBlock.Builder copyConstructorBodyBuilder = CodeBlock.builder();
+
+            for (VariableElement field : fields) {
+                TypeName getMethodType = null;
+
+                final TypeName baseType = TypeName.get(field.asType());
+                final String fieldName = field.getSimpleName().toString();
+
+                TypeName unwrappedType = baseType;
+                TypeName viewClassType = baseType;
+                TypeName initClassType = baseType;
+                TypeName changeClassType = baseType;
+
+                final ConfigValue confAnnotation = 
field.getAnnotation(ConfigValue.class);
+                if (confAnnotation != null) {
+                    getMethodType = Utils.getConfigurationName((ClassName) 
baseType);
+
+                    final FieldSpec nestedConfigField =
+                        FieldSpec
+                            .builder(getMethodType, fieldName, 
Modifier.PRIVATE, FINAL)
+                            .build();
+
+                    configurationClassBuilder.addField(nestedConfigField);
+
+                    constructorBodyBuilder.addStatement("add($L = new 
$T(qualifiedName, $S, false, configurator, this.root))", fieldName, 
getMethodType, fieldName);
+                    copyConstructorBodyBuilder.addStatement("add($L = 
base.$L.copy(this.root))", fieldName, fieldName);
+
+                    unwrappedType = getMethodType;
+                    viewClassType = Utils.getViewName((ClassName) baseType);
+                    initClassType = Utils.getInitName((ClassName) baseType);
+                    changeClassType = Utils.getChangeName((ClassName) 
baseType);
+                }
+
+                final NamedConfigValue namedConfigAnnotation = 
field.getAnnotation(NamedConfigValue.class);
+                if (namedConfigAnnotation != null) {
+                    ClassName fieldType = 
Utils.getConfigurationName((ClassName) baseType);
+
+                    viewClassType = Utils.getViewName((ClassName) baseType);
+                    initClassType = Utils.getInitName((ClassName) baseType);
+                    changeClassType = Utils.getChangeName((ClassName) 
baseType);
+
+                    getMethodType = 
ParameterizedTypeName.get(ClassName.get(NamedListConfiguration.class), 
viewClassType, fieldType, initClassType, changeClassType);
+
+                    final FieldSpec nestedConfigField =
+                        FieldSpec
+                            .builder(getMethodType, fieldName, 
Modifier.PRIVATE, FINAL)
+                            .build();
+
+                    configurationClassBuilder.addField(nestedConfigField);
+
+                    constructorBodyBuilder.addStatement(
+                        "add($L = new $T(qualifiedName, $S, configurator, 
this.root, (p, k) -> new $T(p, k, true, configurator, this.root)))",
+                        fieldName,
+                        getMethodType,
+                        fieldName,
+                        fieldType
+                    );
+
+                    copyConstructorBodyBuilder.addStatement("add($L = 
base.$L.copy(this.root))", fieldName, fieldName);
+                }
+
+                final Value valueAnnotation = field.getAnnotation(Value.class);
+                if (valueAnnotation != null) {
+                    ClassName dynPropClass = 
ClassName.get(DynamicProperty.class);
+
+                    TypeName genericType = baseType;
+
+                    if (genericType.isPrimitive()) {
+                        genericType = genericType.box();
+                    }
+
+                    getMethodType = ParameterizedTypeName.get(dynPropClass, 
genericType);
+
+                    final FieldSpec generatedField = 
FieldSpec.builder(getMethodType, fieldName, Modifier.PRIVATE, FINAL).build();
+
+                    configurationClassBuilder.addField(generatedField);
+
+                    final CodeBlock validatorsBlock = 
ValidationGenerator.generateValidators(field);
+
+                    constructorBodyBuilder.addStatement(

Review comment:
       This whole method is too big and lacks any comments. I don't get what's 
going on.

##########
File path: 
modules/configuration-annotation-processor/src/main/java/org/apache/ignite/configuration/processor/internal/Utils.java
##########
@@ -0,0 +1,204 @@
+/*
+ * 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.configuration.processor.internal;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.VariableElement;
+
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.FieldSpec;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.ParameterizedTypeName;
+import com.squareup.javapoet.TypeName;
+import org.apache.ignite.configuration.internal.DynamicConfiguration;
+import org.apache.ignite.configuration.internal.NamedListConfiguration;
+
+/**
+ * Annotation processing utilities.
+ */
+public class Utils {
+    /** Private constructor. */
+    private Utils() {
+    }
+
+    /**
+     * Create constructor for
+     *
+     * @param fieldSpecs List of fields.
+     * @return Constructor method.
+     */
+    public static MethodSpec createConstructor(List<FieldSpec> fieldSpecs) {
+        final MethodSpec.Builder builder = MethodSpec.constructorBuilder();
+        fieldSpecs.forEach(field -> {
+            builder.addParameter(field.type, field.name);
+            builder.addStatement("this.$L = $L", field.name, field.name);
+        });
+        return builder.build();
+    }
+
+    /**
+     * Create getters for fields.
+     *
+     * @param fieldSpecs List of fields.
+     * @return List of getter methods.
+     */
+    public static List<MethodSpec> createGetters(List<FieldSpec> fieldSpecs) {
+        return fieldSpecs.stream().map(field ->
+            MethodSpec.methodBuilder(field.name)
+             .returns(field.type)
+             .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
+             .addStatement("return $L", field.name)
+             .build()).collect(Collectors.toList()
+        );
+    }
+
+    /**
+     * Create builder-style setters.
+     *
+     * @param fieldSpecs List of fields.
+     * @return List of setter methods.
+     */
+    public static List<MethodSpec> createBuildSetters(List<FieldSpec> 
fieldSpecs) {
+        return fieldSpecs.stream().map(field -> {
+            return MethodSpec.methodBuilder("with" + field.name)
+                .addModifiers(Modifier.PUBLIC, Modifier.FINAL)
+                .addStatement("this.$L = $L", field.name, field.name)
+                .build();
+        }).collect(Collectors.toList());
+    }
+
+    /**
+     * Create '{@code new SomeObject(arg1, arg2, ..., argN)}' code block.
+     *
+     * @param type Type of the new object.
+     * @param fieldSpecs List of arguments.
+     * @return New object code block.
+     */
+    public static CodeBlock newObject(TypeName type, List<VariableElement> 
fieldSpecs) {
+        String args = fieldSpecs.stream().map(f -> 
f.getSimpleName().toString()).collect(Collectors.joining(", "));
+        return CodeBlock.builder()
+            .add("new $T($L)", type, args)
+            .build();
+    }
+
+    /**
+     * Get class with parameters, boxing them if necessary.
+     *
+     * @param clz Generic class.
+     * @param types Generic parameters.
+     * @return Parameterized type.
+     */
+    public static ParameterizedTypeName getParameterized(ClassName clz, 
TypeName... types) {
+        types = Arrays.stream(types).map(t -> {
+            if (t.isPrimitive())
+                t = t.box();
+            return t;
+        }).toArray(TypeName[]::new);
+        return ParameterizedTypeName.get(clz, types);
+    }
+
+    /**
+     * Get {@link ClassName} for configuration class.
+     *
+     * @param schemaClassName Configuration schema ClassName.
+     * @return Configuration ClassName.
+     */
+    public static ClassName getConfigurationName(ClassName schemaClassName) {
+        return ClassName.get(
+            schemaClassName.packageName(),
+            schemaClassName.simpleName().replace("Schema", "")
+        );
+    }
+
+    /**
+     * Get {@link ClassName} for configuration VIEW object class.
+     *
+     * @param schemaClassName Configuration schema ClassName.
+     * @return Configuration VIEW object ClassName.
+     */
+    public static ClassName getViewName(ClassName schemaClassName) {
+        return ClassName.get(
+            schemaClassName.packageName(),
+            schemaClassName.simpleName().replace("ConfigurationSchema", "")
+        );
+    }
+
+    /**
+     * Get {@link ClassName} for configuration INIT object class.
+     *
+     * @param schemaClassName Configuration schema ClassName.
+     * @return Configuration INIT object ClassName.
+     */
+    public static ClassName getInitName(ClassName schemaClassName) {
+        return ClassName.get(
+            schemaClassName.packageName(),
+            "Init" + 
schemaClassName.simpleName().replace("ConfigurationSchema", "")
+        );
+    }
+
+    /**
+     * Get {@link ClassName} for configuration CHANGE object class.
+     *
+     * @param schemaClassName Configuration schema ClassName.
+     * @return Configuration CHANGE object ClassName.
+     */
+    public static ClassName getChangeName(ClassName schemaClassName) {
+        return ClassName.get(
+            schemaClassName.packageName(),
+            "Change" + 
schemaClassName.simpleName().replace("ConfigurationSchema", "")
+        );
+    }
+
+    /**
+     * Check whether type is {@link NamedListConfiguration}.
+     *
+     * @param type Type.
+     * @return {@code true} if type is {@link NamedListConfiguration}.
+     */
+    public static boolean isNamedConfiguration(TypeName type) {
+        if (type instanceof ParameterizedTypeName) {
+            ParameterizedTypeName parameterizedTypeName = 
(ParameterizedTypeName) type;
+
+            if 
(parameterizedTypeName.rawType.equals(ClassName.get(NamedListConfiguration.class)))
+                return true;
+        }
+        return false;
+    }
+
+    /**
+     * Get {@code DynamicConfiguration} inside of the named configuration.
+     *
+     * @param type Type name.
+     * @return {@link DynamicConfiguration} class name.
+     */
+    public static TypeName unwrapNamedListConfigurationClass(TypeName type) {
+        if (type instanceof ParameterizedTypeName) {
+            ParameterizedTypeName parameterizedTypeName = 
(ParameterizedTypeName) type;
+
+            if 
(parameterizedTypeName.rawType.equals(ClassName.get(NamedListConfiguration.class)))
+                return parameterizedTypeName.typeArguments.get(1);
+        }
+
+        throw new RuntimeException(type + " is not a NamedListConfiguration 
class");

Review comment:
       RuntimeException

##########
File path: 
modules/configuration-annotation-processor/src/main/java/org/apache/ignite/configuration/processor/internal/validation/ValidationGenerator.java
##########
@@ -0,0 +1,111 @@
+/*
+ * 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.configuration.processor.internal.validation;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.MirroredTypesException;
+import javax.lang.model.type.TypeMirror;
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+import com.squareup.javapoet.CodeBlock;
+import org.apache.ignite.configuration.internal.DynamicConfiguration;
+import org.apache.ignite.configuration.internal.annotation.Validate;
+import org.apache.ignite.configuration.internal.validation.MaxValidator;
+import org.apache.ignite.configuration.internal.validation.MinValidator;
+import org.apache.ignite.configuration.internal.validation.NotNullValidator;
+
+/**
+ * Class that handles validation generation.
+ */
+public class ValidationGenerator {
+    /** Private constructor. */
+    private ValidationGenerator() {
+    }
+
+    /**
+     * Generate validation block.
+     *
+     * @param variableElement Configuration field.
+     * @return Code block for field validation.
+     */
+    public static CodeBlock generateValidators(VariableElement 
variableElement) {
+        List<CodeBlock> validators = new ArrayList<>();
+        final Min minAnnotation = variableElement.getAnnotation(Min.class);
+        if (minAnnotation != null) {
+            final long minValue = minAnnotation.value();
+            final String message = minAnnotation.message();
+            final CodeBlock build = CodeBlock.builder().add("new $T<$T<?, ?, 
?>>($L, $S)", MinValidator.class, DynamicConfiguration.class, minValue, 
message).build();
+            validators.add(build);
+        }
+
+        final Max maxAnnotation = variableElement.getAnnotation(Max.class);
+        if (maxAnnotation != null) {
+            final long maxValue = maxAnnotation.value();
+            final String message = maxAnnotation.message();
+            final CodeBlock build = CodeBlock.builder().add("new $T<$T<?, ?, 
?>>($L, $S)", MaxValidator.class, DynamicConfiguration.class, maxValue, 
message).build();
+            validators.add(build);
+        }
+
+        final NotNull notNull = variableElement.getAnnotation(NotNull.class);
+        if (notNull != null) {
+            final String message = notNull.message();
+            final CodeBlock build = CodeBlock.builder().add("new $T<$T<?, ?, 
?>>($S)", NotNullValidator.class, DynamicConfiguration.class, message).build();
+            validators.add(build);
+        }
+
+        List<Validate> validateAnnotations = new ArrayList<>();
+
+        final Validate.List validateAnnotationsList = 
variableElement.getAnnotation(Validate.List.class);
+
+        if (validateAnnotationsList != null) {
+            
validateAnnotations.addAll(Arrays.asList(validateAnnotationsList.value()));
+        }
+
+        final Validate validateAnnotationSingle = 
variableElement.getAnnotation(Validate.class);
+
+        if (validateAnnotationSingle != null) {
+            validateAnnotations.add(validateAnnotationSingle);
+        }
+
+        validateAnnotations.forEach(validateAnnotation -> {
+            List<? extends TypeMirror> values = null;
+            try {
+                validateAnnotation.value();
+            } catch (MirroredTypesException e) {
+                values = e.getTypeMirrors();

Review comment:
       I'm sorry, what the hell is this? Please add a comment)

##########
File path: 
modules/configuration-annotation-processor/src/test/java/org/apache/ignite/configuration/processor/internal/ParsedClass.java
##########
@@ -0,0 +1,60 @@
+package org.apache.ignite.configuration.processor.internal;
+
+import com.google.common.base.Functions;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import spoon.reflect.declaration.CtClass;
+import spoon.reflect.declaration.CtConstructor;
+import spoon.reflect.declaration.CtExecutable;
+import spoon.reflect.declaration.CtMethod;
+import spoon.reflect.declaration.CtParameter;
+import spoon.reflect.reference.CtFieldReference;
+import spoon.reflect.reference.CtReference;
+
+public class ParsedClass {

Review comment:
       No javadocs at all

##########
File path: 
modules/configuration/src/main/java/org/apache/ignite/configuration/internal/DynamicConfiguration.java
##########
@@ -0,0 +1,147 @@
+/*
+ * 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.configuration.internal;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.ignite.configuration.internal.property.DynamicProperty;
+import org.apache.ignite.configuration.internal.property.Modifier;
+import org.apache.ignite.configuration.internal.selector.BaseSelectors;
+import org.apache.ignite.configuration.internal.validation.FieldValidator;
+
+/**
+ * This class represents configuration root or node.
+ */
+public abstract class DynamicConfiguration<T, INIT, CHANGE> implements 
Modifier<T, INIT, CHANGE> {

Review comment:
       What is T?

##########
File path: 
modules/configuration/src/main/java/org/apache/ignite/configuration/internal/Configurator.java
##########
@@ -0,0 +1,105 @@
+/*
+ * 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.configuration.internal;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import org.apache.ignite.configuration.internal.property.DynamicProperty;
+import org.apache.ignite.configuration.internal.property.Modifier;
+import org.apache.ignite.configuration.internal.property.PropertyListener;
+import org.apache.ignite.configuration.internal.selector.Selector;
+import org.apache.ignite.configuration.internal.validation.FieldValidator;
+import org.apache.ignite.configuration.internal.validation.MemberKey;
+
+public class Configurator<T extends DynamicConfiguration<?, ?, ?>> {
+
+    private final ConfigurationStorage storage;
+
+    private final T root;
+
+    private final Map<MemberKey, List<FieldValidator<? extends Serializable, ? 
extends DynamicConfiguration<?, ?, ?>>>> fieldValidators = new HashMap<>();
+
+    public Configurator(ConfigurationStorage storage, 
Function<Configurator<T>, T> rootBuilder) {
+        this.storage = storage;
+        this.root = rootBuilder.apply(this);
+        this.init();
+    }
+
+    private void init() {
+        List<DynamicProperty> props = new ArrayList<>();
+
+        props.forEach(property -> {
+            final String key = property.key();
+            property.addListener(new PropertyListener() {
+                @Override public void update(Serializable newValue, Modifier 
modifier) {
+                    storage.save(key, newValue);
+                }
+            });
+            storage.listen(key, serializable -> {
+                property.setSilently(serializable);
+            });
+        });
+    }
+
+    public <TARGET extends Modifier<VIEW, INIT, CHANGE>, VIEW, INIT, CHANGE> 
VIEW getPublic(Selector<T, TARGET, VIEW, INIT, CHANGE> selector) {

Review comment:
       What if we move it to selector? Like "selector.get(cfg)"? Signature will 
be much nicer. Is that an option?

##########
File path: 
modules/configuration-annotation-processor/src/test/java/org/apache/ignite/configuration/processor/internal/ProcessorTest.java
##########
@@ -0,0 +1,93 @@
+/*
+ * 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.configuration.processor.internal;
+
+import com.google.common.base.Functions;
+import com.google.common.collect.ImmutableList;
+import com.google.testing.compile.Compilation;
+import com.google.testing.compile.CompilationSubject;
+import com.google.testing.compile.JavaFileObjects;
+import com.squareup.javapoet.ClassName;
+import java.util.Map;
+import java.util.stream.Collectors;
+import javax.tools.JavaFileObject;
+import org.hamcrest.MatcherAssert;
+import org.junit.Test;
+
+import static com.google.testing.compile.Compiler.javac;
+import static 
org.apache.ignite.configuration.processor.internal.HasFieldMatcher.hasFields;
+import static org.junit.Assert.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class ProcessorTest {

Review comment:
       as well as here

##########
File path: 
modules/configuration/src/main/java/org/apache/ignite/configuration/internal/DynamicConfiguration.java
##########
@@ -0,0 +1,147 @@
+/*
+ * 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.configuration.internal;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.ignite.configuration.internal.property.DynamicProperty;
+import org.apache.ignite.configuration.internal.property.Modifier;
+import org.apache.ignite.configuration.internal.selector.BaseSelectors;
+import org.apache.ignite.configuration.internal.validation.FieldValidator;
+
+/**
+ * This class represents configuration root or node.
+ */
+public abstract class DynamicConfiguration<T, INIT, CHANGE> implements 
Modifier<T, INIT, CHANGE> {
+    /** Fully qualified name of the configuration. */
+    protected final String qualifiedName;
+
+    /** Configuration key. */
+    protected final String key;
+
+    /** Configuration prefix. */
+    protected final String prefix;
+
+    /** Configuration members (leafs and nodes). */

Review comment:
       "leaves"

##########
File path: 
modules/configuration/src/main/java/org/apache/ignite/configuration/internal/DynamicConfiguration.java
##########
@@ -0,0 +1,147 @@
+/*
+ * 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.configuration.internal;
+
+import java.io.Serializable;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.ignite.configuration.internal.property.DynamicProperty;
+import org.apache.ignite.configuration.internal.property.Modifier;
+import org.apache.ignite.configuration.internal.selector.BaseSelectors;
+import org.apache.ignite.configuration.internal.validation.FieldValidator;
+
+/**
+ * This class represents configuration root or node.
+ */
+public abstract class DynamicConfiguration<T, INIT, CHANGE> implements 
Modifier<T, INIT, CHANGE> {
+    /** Fully qualified name of the configuration. */
+    protected final String qualifiedName;
+
+    /** Configuration key. */
+    protected final String key;
+
+    /** Configuration prefix. */
+    protected final String prefix;
+
+    /** Configuration members (leafs and nodes). */
+    protected final Map<String, Modifier<?, ?, ?>> members = new HashMap<>();
+
+    /** Root configuration node. */
+    protected final DynamicConfiguration<?, ?, ?> root;
+
+    /** {@code true} if this is a member of {@link NamedListConfiguration}. */
+    protected final boolean isNamed;
+
+    /** Configurator that this configuration is attached to. */
+    protected final Configurator<? extends DynamicConfiguration<?, ?, ?>> 
configurator;
+
+    /**
+     * Constructor.
+     * @param prefix Configuration prefix.
+     * @param key Configuration key.
+     * @param isNamed Is this a part of named configuration.
+     * @param configurator Configurator that this object is attached to.
+     * @param root Root configuration.
+     */
+    protected DynamicConfiguration(
+        String prefix,
+        String key,
+        boolean isNamed,
+        Configurator<? extends DynamicConfiguration<?, ?, ?>> configurator,
+        DynamicConfiguration<?, ?, ?> root
+    ) {
+        this.prefix = prefix;
+        this.isNamed = isNamed;
+        this.configurator = configurator;
+
+        this.key = key;
+        if (root == null)
+            this.qualifiedName = key;
+        else {
+            if (isNamed)
+                qualifiedName = String.format("%s[%s]", prefix, key);

Review comment:
       Do we still use this formatting somewhere?

##########
File path: 
modules/configuration/src/main/java/org/apache/ignite/configuration/internal/NamedListConfiguration.java
##########
@@ -0,0 +1,125 @@
+/*
+ * 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.configuration.internal;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.BiFunction;
+import java.util.stream.Collectors;
+import org.apache.ignite.configuration.internal.property.Modifier;
+import org.apache.ignite.configuration.internal.property.NamedList;
+
+/**
+ * TODO: Add class description.
+ *
+ * @author @java.author
+ * @version @java.version
+ */
+public class NamedListConfiguration<U, T extends Modifier<U, INIT, CHANGE>, 
INIT, CHANGE> extends DynamicConfiguration<NamedList<U>, NamedList<INIT>, 
NamedList<CHANGE>> {
+    /** Creator of named configuration. */
+    private final BiFunction<String, String, T> creator;
+
+    /** Named configurations. */
+    Map<String, T> values = new HashMap<>();
+
+    /**
+     * Constructor.
+     * @param prefix
+     * @param key
+     * @param configurator
+     * @param root
+     * @param creator
+     */
+    public NamedListConfiguration(
+        String prefix,
+        String key,
+        Configurator<? extends DynamicConfiguration<?, ?, ?>> configurator,
+        DynamicConfiguration<?, ?, ?> root,
+        BiFunction<String, String, T> creator
+    ) {
+        super(prefix, key, false, configurator, root);
+        this.creator = creator;
+    }
+
+    /**
+     * Constructor.
+     * @param base
+     * @param configurator
+     * @param root
+     */
+    private NamedListConfiguration(
+        NamedListConfiguration<U, T, INIT, CHANGE> base,
+        Configurator<? extends DynamicConfiguration<?, ?, ?>> configurator,
+        DynamicConfiguration<?, ?, ?> root
+    ) {
+        super(base.prefix, base.key, false, configurator, root);
+
+        this.creator = base.creator;
+
+        base.values.forEach((key, value) -> {
+            final T copy = (T) ((DynamicConfiguration<U, INIT, CHANGE>) 
value).copy(root);

Review comment:
       oof, this is rough. Something's wrong. Do we have to have "T extends 
Modifier<U, INIT, CHANGE>" instead of just "Modifier<U, INIT, CHANGE>". This 
might be a stupid question because I don't understand meaning of these 
parameters :)

##########
File path: 
modules/configuration/src/main/java/org/apache/ignite/configuration/internal/annotation/Validate.java
##########
@@ -0,0 +1,77 @@
+/*
+ * 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.configuration.internal.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Repeatable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import org.apache.ignite.configuration.internal.validation.FieldValidator;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+/**
+ * This annotation applies custom validation to configuration field, for 
example:
+ * <pre name="code" class="java">
+ * public class ConfSchema {
+ *     {@literal @}Validate(SomeCustomValidator.class)
+ *     private String value;
+ * }
+ * </pre>
+ *
+ * If you need multiple custom validations:
+ * <pre name="code" class="java">
+ * public class ConfSchema {
+ *     {@literal @}Validate.List({

Review comment:
       No no no no no
   You just write several annotations, that's it. That's the whole point of 
_repeatable_ annotations.

##########
File path: 
modules/configuration/src/main/java/org/apache/ignite/configuration/internal/NamedListConfiguration.java
##########
@@ -0,0 +1,125 @@
+/*
+ * 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.configuration.internal;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.function.BiFunction;
+import java.util.stream.Collectors;
+import org.apache.ignite.configuration.internal.property.Modifier;
+import org.apache.ignite.configuration.internal.property.NamedList;
+
+/**
+ * TODO: Add class description.
+ *
+ * @author @java.author
+ * @version @java.version
+ */
+public class NamedListConfiguration<U, T extends Modifier<U, INIT, CHANGE>, 
INIT, CHANGE> extends DynamicConfiguration<NamedList<U>, NamedList<INIT>, 
NamedList<CHANGE>> {
+    /** Creator of named configuration. */
+    private final BiFunction<String, String, T> creator;
+
+    /** Named configurations. */
+    Map<String, T> values = new HashMap<>();

Review comment:
       Why not "private"? Do you use it in tests?

##########
File path: 
modules/configuration/src/main/java/org/apache/ignite/configuration/internal/annotation/Config.java
##########
@@ -0,0 +1,69 @@
+/*
+ * 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.configuration.internal.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import org.apache.ignite.configuration.internal.DynamicConfiguration;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+/**
+ * This annotation, if applied to a class, marks it as a configuration schema.
+ * Annotation processor generates a couple of classes for each configuration 
schema:

Review comment:
       4 is not a couple, it's "several"

##########
File path: 
modules/configuration/src/main/java/org/apache/ignite/configuration/internal/selector/BaseSelectors.java
##########
@@ -0,0 +1,125 @@
+/*
+ * 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.configuration.internal.selector;
+
+import java.lang.invoke.MethodHandle;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import org.apache.ignite.configuration.internal.DynamicConfiguration;
+import org.apache.ignite.configuration.internal.property.Modifier;
+
+/**
+ * Base selector holder.
+ */
+public class BaseSelectors {
+    /** Map from string representation of selector to {@link SelectorHolder}. 
*/
+    private static final Map<String, SelectorHolder> selectors = new 
HashMap<>();
+
+    /**
+     * Get selector from selectors map by key.
+     *
+     * Valid formats for selector key:
+     * <ul>
+     *     <li>root.inner.option.field in case of static config field</li>
+     *     <li>root.inner.named[name].field in case of dynamic (named) config 
field</li>
+     * </ul>
+     *
+     * @param name Selector name.
+     * @return Selector.
+     */
+    public static <A extends DynamicConfiguration<?, ?, ?>, B extends 
Modifier<C, D, E>, C, D, E> Selector<A, B, C, D, E> find(String name) {
+        String[] splitten = name.split("\\.");

Review comment:
       Naming is weird. First of all, no one uses the word "splitten", second - 
we can name it, like, "names" of "propNames", you know?

##########
File path: 
modules/configuration/src/main/java/org/apache/ignite/configuration/internal/selector/BaseSelectors.java
##########
@@ -0,0 +1,125 @@
+/*
+ * 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.configuration.internal.selector;
+
+import java.lang.invoke.MethodHandle;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import org.apache.ignite.configuration.internal.DynamicConfiguration;
+import org.apache.ignite.configuration.internal.property.Modifier;
+
+/**
+ * Base selector holder.
+ */
+public class BaseSelectors {
+    /** Map from string representation of selector to {@link SelectorHolder}. 
*/
+    private static final Map<String, SelectorHolder> selectors = new 
HashMap<>();
+
+    /**
+     * Get selector from selectors map by key.
+     *
+     * Valid formats for selector key:
+     * <ul>
+     *     <li>root.inner.option.field in case of static config field</li>
+     *     <li>root.inner.named[name].field in case of dynamic (named) config 
field</li>
+     * </ul>
+     *
+     * @param name Selector name.
+     * @return Selector.
+     */
+    public static <A extends DynamicConfiguration<?, ?, ?>, B extends 
Modifier<C, D, E>, C, D, E> Selector<A, B, C, D, E> find(String name) {
+        String[] splitten = name.split("\\.");
+        List<String> arguments = new ArrayList<>();

Review comment:
       Not enough empty lines here.

##########
File path: 
modules/configuration/src/main/java/org/apache/ignite/configuration/internal/validation/FieldValidator.java
##########
@@ -0,0 +1,46 @@
+/*
+ * 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.configuration.internal.validation;
+
+import java.io.Serializable;
+import org.apache.ignite.configuration.internal.DynamicConfiguration;
+
+/**
+ * Base class for field validator. Contains exception message.
+ * @param <T> Field type.
+ * @param <C> Root configuration type.
+ */
+public abstract class FieldValidator<T extends Serializable, C extends 
DynamicConfiguration<?, ?, ?>> {
+    /** Validation error message. */
+    protected final String message;
+
+    /** Constructor. */
+    protected FieldValidator(String message) {

Review comment:
       This is a value from annotation, right?

##########
File path: 
modules/configuration/src/main/java/org/apache/ignite/configuration/internal/selector/BaseSelectors.java
##########
@@ -0,0 +1,125 @@
+/*
+ * 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.configuration.internal.selector;
+
+import java.lang.invoke.MethodHandle;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import org.apache.ignite.configuration.internal.DynamicConfiguration;
+import org.apache.ignite.configuration.internal.property.Modifier;
+
+/**
+ * Base selector holder.
+ */
+public class BaseSelectors {
+    /** Map from string representation of selector to {@link SelectorHolder}. 
*/
+    private static final Map<String, SelectorHolder> selectors = new 
HashMap<>();
+
+    /**
+     * Get selector from selectors map by key.
+     *
+     * Valid formats for selector key:
+     * <ul>
+     *     <li>root.inner.option.field in case of static config field</li>
+     *     <li>root.inner.named[name].field in case of dynamic (named) config 
field</li>
+     * </ul>
+     *
+     * @param name Selector name.
+     * @return Selector.
+     */
+    public static <A extends DynamicConfiguration<?, ?, ?>, B extends 
Modifier<C, D, E>, C, D, E> Selector<A, B, C, D, E> find(String name) {

Review comment:
       A B C D E

##########
File path: 
modules/configuration/src/main/java/org/apache/ignite/configuration/internal/annotation/Value.java
##########
@@ -0,0 +1,40 @@
+/*
+ * 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.configuration.internal.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import org.apache.ignite.configuration.internal.property.DynamicProperty;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+/**
+ * This annotation marks configuration schema field as a configuration tree 
leaf.
+ * Every field annotated with this annotation will produce a {@link 
DynamicProperty} field in generated configuration class.
+ */
+@Target({ FIELD })
+@Retention(SOURCE)
+@Documented
+public @interface Value {
+    /**
+     * @return {@code true} if this value must only be init and can't be 
changed afterwards.
+     */
+    boolean immutable() default false;

Review comment:
       Double negation =) Let's leave it as is, it's just funny.

##########
File path: 
modules/configuration/src/main/java/org/apache/ignite/configuration/internal/property/NamedList.java
##########
@@ -0,0 +1,51 @@
+/*
+ * 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.configuration.internal.property;
+
+import java.util.Map;
+
+/**
+ * This class holds named configurations in VIEW object.
+ */
+public class NamedList<T> {
+    /** Named values. */
+    private final Map<String, T> values;
+
+    /**
+     * Constructor.
+     * @param values Named values.
+     */
+    public NamedList(Map<String, T> values) {
+        this.values = values;
+    }
+
+    /**
+     * Get named values.
+     * @return Named values.
+     */
+    public Map<String, T> getValues() {
+        return values;
+    }
+
+    /** {@inheritDoc} */
+    @Override public String toString() {
+        return "NamedList{" +

Review comment:
       Auto-generated implementation, we usually use "square" brackets.

##########
File path: 
modules/configuration/src/main/java/org/apache/ignite/configuration/internal/validation/FieldValidator.java
##########
@@ -0,0 +1,46 @@
+/*
+ * 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.configuration.internal.validation;
+
+import java.io.Serializable;
+import org.apache.ignite.configuration.internal.DynamicConfiguration;
+
+/**
+ * Base class for field validator. Contains exception message.
+ * @param <T> Field type.
+ * @param <C> Root configuration type.
+ */
+public abstract class FieldValidator<T extends Serializable, C extends 
DynamicConfiguration<?, ?, ?>> {
+    /** Validation error message. */
+    protected final String message;
+
+    /** Constructor. */
+    protected FieldValidator(String message) {
+        this.message = message;
+    }
+
+    /**
+     * Validate field.
+     *
+     * @param value New value.
+     * @param newRoot New configuration root.
+     * @param oldRoot Old configuration root.
+     */
+    public abstract void validate(T value, C newRoot, C oldRoot);

Review comment:
       Does this method have to throw some exception? What type of exception? 
How do we distinguish regular validation error from runtime problem? It must be 
reflected in signature and documentation.

##########
File path: 
modules/configuration-annotation-processor/src/main/java/org/apache/ignite/configuration/processor/internal/Utils.java
##########
@@ -0,0 +1,204 @@
+/*
+ * 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.configuration.processor.internal;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.VariableElement;
+
+import com.squareup.javapoet.ClassName;
+import com.squareup.javapoet.CodeBlock;
+import com.squareup.javapoet.FieldSpec;
+import com.squareup.javapoet.MethodSpec;
+import com.squareup.javapoet.ParameterizedTypeName;
+import com.squareup.javapoet.TypeName;
+import org.apache.ignite.configuration.internal.DynamicConfiguration;
+import org.apache.ignite.configuration.internal.NamedListConfiguration;
+
+/**
+ * Annotation processing utilities.
+ */
+public class Utils {
+    /** Private constructor. */
+    private Utils() {
+    }
+
+    /**
+     * Create constructor for
+     *
+     * @param fieldSpecs List of fields.
+     * @return Constructor method.
+     */
+    public static MethodSpec createConstructor(List<FieldSpec> fieldSpecs) {
+        final MethodSpec.Builder builder = MethodSpec.constructorBuilder();
+        fieldSpecs.forEach(field -> {

Review comment:
       Looks weird

##########
File path: 
modules/configuration/src/main/java/org/apache/ignite/configuration/internal/validation/MaxValidator.java
##########
@@ -0,0 +1,42 @@
+/*
+ * 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.configuration.internal.validation;
+
+import org.apache.ignite.configuration.internal.DynamicConfiguration;
+
+/**
+ * Validate that field value is not greater than some maximum value.
+ *
+ * @param <C> Root configuration type.
+ */
+public class MaxValidator<C extends DynamicConfiguration<?, ?, ?>> extends 
FieldValidator<Number, C> {
+    /** Maximum value. */
+    private final long maxValue;
+
+    /** Constructor. */
+    public MaxValidator(long maxValue, String message) {
+        super(message);
+        this.maxValue = maxValue;
+    }
+
+    /** {@inheritDoc} */
+    @Override public void validate(Number value, C newRoot, C oldRoot) {
+        if (value.longValue() > maxValue)
+            throw new ConfigurationValidationException(message);

Review comment:
       So, this is a runtime exception, but why?

##########
File path: 
modules/configuration/src/main/java/org/apache/ignite/configuration/internal/selector/BaseSelectors.java
##########
@@ -0,0 +1,125 @@
+/*
+ * 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.configuration.internal.selector;
+
+import java.lang.invoke.MethodHandle;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import org.apache.ignite.configuration.internal.DynamicConfiguration;
+import org.apache.ignite.configuration.internal.property.Modifier;
+
+/**
+ * Base selector holder.
+ */
+public class BaseSelectors {
+    /** Map from string representation of selector to {@link SelectorHolder}. 
*/
+    private static final Map<String, SelectorHolder> selectors = new 
HashMap<>();
+
+    /**
+     * Get selector from selectors map by key.
+     *
+     * Valid formats for selector key:
+     * <ul>
+     *     <li>root.inner.option.field in case of static config field</li>
+     *     <li>root.inner.named[name].field in case of dynamic (named) config 
field</li>
+     * </ul>
+     *
+     * @param name Selector name.
+     * @return Selector.
+     */
+    public static <A extends DynamicConfiguration<?, ?, ?>, B extends 
Modifier<C, D, E>, C, D, E> Selector<A, B, C, D, E> find(String name) {

Review comment:
       Who's going to use this method? I see that it uses that format with 
brackets for named configurations, but it's not public, right?

##########
File path: 
modules/configuration-annotation-processor/src/test/resources/org/apache/ignite/configuration/processor/internal/TestConfigurationSchema.java
##########
@@ -0,0 +1,22 @@
+package org.apache.ignite.configuration.processor.internal;
+
+import org.apache.ignite.configuration.internal.annotation.Config;
+import org.apache.ignite.configuration.internal.annotation.Value;
+
+@Config(value = "test", root = true)
+public class TestConfigurationSchema {
+    @Value
+    private String value1;
+
+    @Value
+    private long primitiveLong;
+
+    @Value
+    private Long boxedLong;
+
+    @Value
+    private int primitiveInt;
+
+    @Value
+    private Integer boxedInt;
+}

Review comment:
       No empty line. And you forgot about comments




----------------------------------------------------------------
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.

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


Reply via email to