This is an automated email from the ASF dual-hosted git repository.

apolovtsev pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git


The following commit(s) were added to refs/heads/main by this push:
     new 747db12571 IGNITE-24208 Refactor configuration annotation processor 
(Part 1) (#5045)
747db12571 is described below

commit 747db1257147b945e0d3553a942fd52bacb945b1
Author: Alexander Polovtcev <[email protected]>
AuthorDate: Wed Jan 15 13:24:31 2025 +0200

    IGNITE-24208 Refactor configuration annotation processor (Part 1) (#5045)
---
 .../configuration/processor/ClassWrapper.java      | 113 +++++++
 .../processor/ConfigurationProcessor.java          | 354 +++++++++------------
 .../processor/ConfigurationProcessorUtils.java     |  66 ++--
 .../ConfigurationValidationException.java          |  27 ++
 .../InjectedValueValidator.java                    |  15 +-
 5 files changed, 333 insertions(+), 242 deletions(-)

diff --git 
a/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/internal/configuration/processor/ClassWrapper.java
 
b/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/internal/configuration/processor/ClassWrapper.java
new file mode 100644
index 0000000000..f4cd41c768
--- /dev/null
+++ 
b/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/internal/configuration/processor/ClassWrapper.java
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.configuration.processor;
+
+import static java.util.stream.Collectors.toList;
+import static javax.lang.model.element.Modifier.STATIC;
+import static 
org.apache.ignite.internal.configuration.processor.ConfigurationProcessorUtils.sameType;
+
+import java.lang.annotation.Annotation;
+import java.util.List;
+import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.TypeMirror;
+import org.apache.ignite.internal.util.Lazy;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * A wrapper around a class (represented by a {@link TypeElement}) with some 
helper methods.
+ */
+public class ClassWrapper {
+    private final ProcessingEnvironment processingEnvironment;
+
+    private final TypeElement clazz;
+
+    private final List<VariableElement> fields;
+
+    private final Lazy<ClassWrapper> superClass = new 
Lazy<>(this::computeSuperClass);
+
+    /** Constructor. */
+    public ClassWrapper(ProcessingEnvironment processingEnvironment, 
TypeElement clazz) {
+        this.processingEnvironment = processingEnvironment;
+        this.clazz = clazz;
+        this.fields = fields(clazz);
+    }
+
+    public TypeElement clazz() {
+        return clazz;
+    }
+
+    public <A extends Annotation> A getAnnotation(Class<A> annotationType) {
+        return clazz.getAnnotation(annotationType);
+    }
+
+    /**
+     * Returns the superclass of the class, or {@code null} if the superclass 
is {@link Object}.
+     */
+    public @Nullable ClassWrapper superClass() {
+        return superClass.get();
+    }
+
+    /**
+     * Returns the superclass of the class, or throws {@link 
ConfigurationValidationException} if the superclass is {@link Object}.
+     */
+    public ClassWrapper requiredSuperClass() {
+        ClassWrapper superClass = superClass();
+
+        if (superClass == null) {
+            throw new ConfigurationValidationException(this, "Must have a 
superclass");
+        }
+
+        return superClass;
+    }
+
+    private @Nullable ClassWrapper computeSuperClass() {
+        TypeMirror superClassType = clazz.getSuperclass();
+
+        if (sameType(processingEnvironment, superClassType, Object.class)) {
+            return null;
+        }
+
+        var superType = (TypeElement) 
processingEnvironment.getTypeUtils().asElement(superClassType);
+
+        return new ClassWrapper(processingEnvironment, superType);
+    }
+
+    private static List<VariableElement> fields(TypeElement type) {
+        return type.getEnclosedElements().stream()
+                .filter(el -> el.getKind() == ElementKind.FIELD)
+                .filter(el -> !el.getModifiers().contains(STATIC)) // ignore 
static members
+                .map(VariableElement.class::cast)
+                .collect(toList());
+    }
+
+    public List<VariableElement> fields() {
+        return fields;
+    }
+
+    public List<VariableElement> fieldsAnnotatedWith(Class<? extends 
Annotation> annotationClass) {
+        return fields.stream().filter(f -> f.getAnnotation(annotationClass) != 
null).collect(toList());
+    }
+
+    @Override
+    public String toString() {
+        return clazz.getQualifiedName().toString();
+    }
+}
diff --git 
a/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/internal/configuration/processor/ConfigurationProcessor.java
 
b/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/internal/configuration/processor/ConfigurationProcessor.java
index 3dc7f7007a..934a8a5658 100644
--- 
a/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/internal/configuration/processor/ConfigurationProcessor.java
+++ 
b/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/internal/configuration/processor/ConfigurationProcessor.java
@@ -23,9 +23,7 @@ import static javax.lang.model.element.Modifier.ABSTRACT;
 import static javax.lang.model.element.Modifier.FINAL;
 import static javax.lang.model.element.Modifier.PUBLIC;
 import static javax.lang.model.element.Modifier.STATIC;
-import static 
org.apache.ignite.internal.configuration.processor.ConfigurationProcessorUtils.collectFieldsWithAnnotation;
 import static 
org.apache.ignite.internal.configuration.processor.ConfigurationProcessorUtils.containsAnyAnnotation;
-import static 
org.apache.ignite.internal.configuration.processor.ConfigurationProcessorUtils.findFirstPresentAnnotation;
 import static 
org.apache.ignite.internal.configuration.processor.ConfigurationProcessorUtils.getChangeName;
 import static 
org.apache.ignite.internal.configuration.processor.ConfigurationProcessorUtils.getConfigurationInterfaceName;
 import static 
org.apache.ignite.internal.configuration.processor.ConfigurationProcessorUtils.getViewName;
@@ -49,6 +47,7 @@ import com.squareup.javapoet.WildcardTypeName;
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.lang.annotation.Annotation;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.List;
 import java.util.Optional;
@@ -89,7 +88,7 @@ import 
org.apache.ignite.configuration.annotation.PolymorphicConfigInstance;
 import org.apache.ignite.configuration.annotation.PolymorphicId;
 import org.apache.ignite.configuration.annotation.Secret;
 import org.apache.ignite.configuration.annotation.Value;
-import 
org.apache.ignite.internal.configuration.processor.validators.InjectedValueValidator;
+import 
org.apache.ignite.internal.configuration.processor.validation.InjectedValueValidator;
 import org.jetbrains.annotations.Nullable;
 
 /**
@@ -98,6 +97,15 @@ import org.jetbrains.annotations.Nullable;
 // TODO: IGNITE-17166 Split into classes/methods for 
regular/internal/polymorphic/abstract configuration
 @AutoService(Processor.class)
 public class ConfigurationProcessor extends AbstractProcessor {
+    public static final Set<Class<? extends Annotation>> TOP_LEVEL_ANNOTATIONS 
= Set.of(
+            Config.class,
+            ConfigurationRoot.class,
+            ConfigurationExtension.class,
+            PolymorphicConfig.class,
+            PolymorphicConfigInstance.class,
+            AbstractConfiguration.class
+    );
+
     /** Java file padding. */
     private static final String INDENT = "    ";
 
@@ -121,7 +129,6 @@ public class ConfigurationProcessor extends 
AbstractProcessor {
     /** Postfix with which any configuration schema class name must end. */
     private static final String CONFIGURATION_SCHEMA_POSTFIX = 
"ConfigurationSchema";
 
-    /** {@inheritDoc} */
     @Override
     public boolean process(Set<? extends TypeElement> annotations, 
RoundEnvironment roundEnvironment) {
         try {
@@ -146,7 +153,7 @@ public class ConfigurationProcessor extends 
AbstractProcessor {
 
         // All classes annotated with {@link #supportedAnnotationTypes}.
         List<TypeElement> annotatedConfigs = roundEnvironment
-                .getElementsAnnotatedWithAny(supportedAnnotationTypes())
+                .getElementsAnnotatedWithAny(TOP_LEVEL_ANNOTATIONS)
                 .stream()
                 .filter(element -> element.getKind() == ElementKind.CLASS)
                 .map(TypeElement.class::cast)
@@ -159,12 +166,11 @@ public class ConfigurationProcessor extends 
AbstractProcessor {
         var injectedValueValidator = new InjectedValueValidator(processingEnv);
 
         for (TypeElement clazz : annotatedConfigs) {
-            // Find all the fields of the schema.
-            List<VariableElement> fields = fields(clazz);
+            var classWrapper = new ClassWrapper(processingEnv, clazz);
 
-            validateConfigurationSchemaClass(clazz, fields);
+            validateConfigurationSchemaClass(classWrapper);
 
-            injectedValueValidator.validate(clazz, fields);
+            injectedValueValidator.validate(classWrapper);
 
             // Get package name of the schema class
             String packageName = 
elementUtils.getPackageOf(clazz).getQualifiedName().toString();
@@ -177,7 +183,7 @@ public class ConfigurationProcessor extends 
AbstractProcessor {
             TypeSpec.Builder configurationInterfaceBuilder = 
TypeSpec.interfaceBuilder(configInterface)
                     .addModifiers(PUBLIC);
 
-            for (VariableElement field : fields) {
+            for (VariableElement field : classWrapper.fields()) {
                 if (!field.getModifiers().contains(PUBLIC)) {
                     throw new ConfigurationProcessorException("Field " + 
clazz.getQualifiedName() + "." + field + " must be public");
                 }
@@ -259,11 +265,10 @@ public class ConfigurationProcessor extends 
AbstractProcessor {
 
             // Create VIEW and CHANGE classes.
             createPojoBindings(
-                    fields,
+                    classWrapper,
                     schemaClassName,
                     configurationInterfaceBuilder,
                     (isExtendingConfig && !isRootConfig) || 
isPolymorphicInstance,
-                    clazz,
                     isPolymorphicConfig,
                     isPolymorphicInstance
             );
@@ -271,10 +276,11 @@ public class ConfigurationProcessor extends 
AbstractProcessor {
             if (isRootConfig) {
                 createRootKeyField(configInterface, 
configurationInterfaceBuilder, schemaClassName, clazz);
             } else if (isExtendingConfig) {
-                TypeElement superClass = superClass(clazz);
-                boolean isSuperClassRootConfig = 
superClass.getAnnotation(ConfigurationRoot.class) != null;
+                ClassWrapper superClass = classWrapper.superClass();
+
+                boolean isSuperClassRootConfig = superClass != null && 
superClass.getAnnotation(ConfigurationRoot.class) != null;
                 if (isSuperClassRootConfig) {
-                    createExtensionKeyField(configInterface, 
configurationInterfaceBuilder, ClassName.get(superClass));
+                    createExtensionKeyField(configInterface, 
configurationInterfaceBuilder, ClassName.get(superClass.clazz()));
                 }
             }
 
@@ -411,20 +417,17 @@ public class ConfigurationProcessor extends 
AbstractProcessor {
     /**
      * Create VIEW and CHANGE classes and methods.
      *
-     * @param fields Collection of configuration fields.
      * @param schemaClassName Class name of schema.
      * @param configurationInterfaceBuilder Configuration interface builder.
      * @param extendBaseSchema {@code true} if extending base schema 
interfaces.
-     * @param realSchemaClass Class descriptor.
      * @param isPolymorphicConfig Is a polymorphic configuration.
      * @param isPolymorphicInstanceConfig Is an instance of polymorphic 
configuration.
      */
     private void createPojoBindings(
-            Collection<VariableElement> fields,
+            ClassWrapper classWrapper,
             ClassName schemaClassName,
             TypeSpec.Builder configurationInterfaceBuilder,
             boolean extendBaseSchema,
-            TypeElement realSchemaClass,
             boolean isPolymorphicConfig,
             boolean isPolymorphicInstanceConfig
     ) {
@@ -435,13 +438,13 @@ public class ConfigurationProcessor extends 
AbstractProcessor {
         @Nullable TypeName viewBaseSchemaInterfaceType;
         @Nullable TypeName changeBaseSchemaInterfaceType;
 
-        TypeElement superClass = superClass(realSchemaClass);
+        ClassWrapper superClass = classWrapper.superClass();
 
-        boolean isSuperClassAbstractConfiguration = 
!isClass(superClass.asType(), Object.class)
+        boolean isSuperClassAbstractConfiguration = superClass != null
                 && superClass.getAnnotation(AbstractConfiguration.class) != 
null;
 
-        if (extendBaseSchema || isSuperClassAbstractConfiguration) {
-            ClassName superClassSchemaClassName = ClassName.get(superClass);
+        if (superClass != null && (extendBaseSchema || 
isSuperClassAbstractConfiguration)) {
+            ClassName superClassSchemaClassName = 
ClassName.get(superClass.clazz());
 
             viewBaseSchemaInterfaceType = 
getViewName(superClassSchemaClassName);
             changeBaseSchemaInterfaceType = 
getChangeName(superClassSchemaClassName);
@@ -460,7 +463,7 @@ public class ConfigurationProcessor extends 
AbstractProcessor {
         } else {
             ClassName confTreeInterface = 
ClassName.get("org.apache.ignite.configuration", "ConfigurationTree");
 
-            if (realSchemaClass.getAnnotation(AbstractConfiguration.class) != 
null) {
+            if (classWrapper.getAnnotation(AbstractConfiguration.class) != 
null) {
                 // Example: TableConfig<VIEWT extends TableView, CHANGET 
extends TableChange> extends ConfigurationTree<VIEWT, CHANGET>
                 configurationInterfaceBuilder.addTypeVariables(List.of(
                         TypeVariableName.get("VIEWT", viewClsName),
@@ -508,7 +511,7 @@ public class ConfigurationProcessor extends 
AbstractProcessor {
 
         ClassName consumerClsName = ClassName.get(Consumer.class);
 
-        for (VariableElement field : fields) {
+        for (VariableElement field : classWrapper.fields()) {
             String fieldName = field.getSimpleName().toString();
             TypeMirror schemaFieldType = field.asType();
             TypeName schemaFieldTypeName = TypeName.get(schemaFieldType);
@@ -641,184 +644,134 @@ public class ConfigurationProcessor extends 
AbstractProcessor {
         return isClass(type, String.class) || isClass(type, UUID.class);
     }
 
-    /**
-     * Get class fields.
-     *
-     * @param type Class type.
-     * @return Class fields.
-     */
-    private static List<VariableElement> fields(TypeElement type) {
-        return type.getEnclosedElements().stream()
-                .filter(el -> el.getKind() == ElementKind.FIELD)
-                .filter(el -> !el.getModifiers().contains(STATIC)) // ignore 
static members
-                .map(VariableElement.class::cast)
-                .collect(toList());
-    }
-
     /**
      * Validate the class.
      *
-     * @param clazz Class type.
-     * @param fields Class fields.
      * @throws ConfigurationProcessorException If the class validation fails.
      */
-    private void validateConfigurationSchemaClass(TypeElement clazz, 
List<VariableElement> fields) {
-        if 
(!clazz.getSimpleName().toString().endsWith(CONFIGURATION_SCHEMA_POSTFIX)) {
+    private void validateConfigurationSchemaClass(ClassWrapper classWrapper) {
+        if 
(!classWrapper.clazz().getSimpleName().toString().endsWith(CONFIGURATION_SCHEMA_POSTFIX))
 {
             throw new ConfigurationProcessorException(
-                    String.format("%s must end with '%s'", 
clazz.getQualifiedName(), CONFIGURATION_SCHEMA_POSTFIX));
+                    String.format("%s must end with '%s'", 
classWrapper.clazz().getQualifiedName(), CONFIGURATION_SCHEMA_POSTFIX));
         }
 
-        if (clazz.getAnnotation(ConfigurationExtension.class) != null) {
-            validateExtensionConfiguration(clazz, fields);
-        } else if (clazz.getAnnotation(PolymorphicConfig.class) != null) {
-            validatePolymorphicConfig(clazz, fields);
-        } else if (clazz.getAnnotation(PolymorphicConfigInstance.class) != 
null) {
-            validatePolymorphicConfigInstance(clazz, fields);
-        } else if (clazz.getAnnotation(AbstractConfiguration.class) != null) {
-            validateAbstractConfiguration(clazz, fields);
-        } else if (clazz.getAnnotation(ConfigurationRoot.class) != null) {
-            validateConfigurationRoot(clazz, fields);
-        } else if (clazz.getAnnotation(Config.class) != null) {
-            validateConfig(clazz, fields);
+        if (classWrapper.getAnnotation(ConfigurationExtension.class) != null) {
+            validateExtensionConfiguration(classWrapper);
+        } else if (classWrapper.getAnnotation(PolymorphicConfig.class) != 
null) {
+            validatePolymorphicConfig(classWrapper);
+        } else if (classWrapper.getAnnotation(PolymorphicConfigInstance.class) 
!= null) {
+            validatePolymorphicConfigInstance(classWrapper);
+        } else if (classWrapper.getAnnotation(AbstractConfiguration.class) != 
null) {
+            validateAbstractConfiguration(classWrapper);
+        } else if (classWrapper.getAnnotation(ConfigurationRoot.class) != 
null) {
+            validateConfigurationRoot(classWrapper);
+        } else if (classWrapper.getAnnotation(Config.class) != null) {
+            validateConfig(classWrapper);
         }
 
-        validateInjectedNameFields(clazz, fields);
+        validateInjectedNameFields(classWrapper);
 
-        validateNameFields(clazz, fields);
+        validateNameFields(classWrapper);
     }
 
     /**
      * Checks configuration schema with {@link ConfigurationExtension}.
-     *
-     * @param clazz Type element under validation.
-     * @param fields Non-static fields of the class under validation.
      */
-    private void validateExtensionConfiguration(TypeElement clazz, 
List<VariableElement> fields) {
+    private void validateExtensionConfiguration(ClassWrapper classWrapper) {
         checkIncompatibleClassAnnotations(
-                clazz,
+                classWrapper.clazz(),
                 ConfigurationExtension.class,
                 
incompatibleSchemaClassAnnotations(ConfigurationExtension.class, 
ConfigurationRoot.class)
         );
 
-        checkNotContainsPolymorphicIdField(clazz, 
ConfigurationExtension.class, fields);
+        checkNotContainsPolymorphicIdField(classWrapper, 
ConfigurationExtension.class);
 
-        if (clazz.getAnnotation(ConfigurationRoot.class) != null) {
-            checkNotExistSuperClass(clazz, ConfigurationExtension.class);
+        if (classWrapper.getAnnotation(ConfigurationRoot.class) != null) {
+            checkNotExistSuperClass(classWrapper.clazz(), 
ConfigurationExtension.class);
         } else {
-            checkExistSuperClass(clazz, ConfigurationExtension.class);
+            checkExistSuperClass(classWrapper.clazz(), 
ConfigurationExtension.class);
 
-            TypeElement superClazz = superClass(clazz);
+            ClassWrapper superClassWrapper = classWrapper.requiredSuperClass();
 
-            if (superClazz.getAnnotation(ConfigurationExtension.class) != 
null) {
+            if (superClassWrapper.getAnnotation(ConfigurationExtension.class) 
!= null) {
                 throw new ConfigurationProcessorException(String.format(
                         "Superclass must not have %s: %s",
                         simpleName(ConfigurationExtension.class),
-                        clazz.getQualifiedName()
+                        classWrapper.clazz().getQualifiedName()
                 ));
             }
 
-            checkSuperclassContainAnyAnnotation(clazz, superClazz, 
ConfigurationRoot.class, Config.class);
+            checkSuperclassContainAnyAnnotation(classWrapper.clazz(), 
superClassWrapper.clazz(), ConfigurationRoot.class, Config.class);
 
-            checkNoConflictFieldNames(clazz, superClazz, fields, 
fields(superClazz));
+            checkNoConflictFieldNames(classWrapper, superClassWrapper);
         }
     }
 
     /**
      * Checks configuration schema with {@link PolymorphicConfig}.
-     *
-     * @param clazz Type element under validation.
-     * @param fields Non-static fields of the class under validation.
      */
-    private void validatePolymorphicConfig(TypeElement clazz, 
List<VariableElement> fields) {
+    private void validatePolymorphicConfig(ClassWrapper classWrapper) {
         checkIncompatibleClassAnnotations(
-                clazz,
+                classWrapper.clazz(),
                 PolymorphicConfig.class,
                 incompatibleSchemaClassAnnotations(PolymorphicConfig.class)
         );
 
-        checkNotExistSuperClass(clazz, PolymorphicConfig.class);
+        checkNotExistSuperClass(classWrapper.clazz(), PolymorphicConfig.class);
 
-        List<VariableElement> typeIdFields = 
collectFieldsWithAnnotation(fields, PolymorphicId.class);
+        List<VariableElement> typeIdFields = 
classWrapper.fieldsAnnotatedWith(PolymorphicId.class);
 
-        if (typeIdFields.size() != 1 || fields.indexOf(typeIdFields.get(0)) != 
0) {
+        if (typeIdFields.size() != 1 || 
classWrapper.fields().indexOf(typeIdFields.get(0)) != 0) {
             throw new ConfigurationProcessorException(String.format(
                     "Class with %s must contain one field with %s and it 
should be the first in the schema: %s",
                     simpleName(PolymorphicConfig.class),
                     simpleName(PolymorphicId.class),
-                    clazz.getQualifiedName()
+                    classWrapper.clazz().getQualifiedName()
             ));
         }
     }
 
     /**
      * Checks configuration schema with {@link PolymorphicConfigInstance}.
-     *
-     * @param clazz Type element under validation.
-     * @param fields Non-static fields of the class under validation.
      */
-    private void validatePolymorphicConfigInstance(TypeElement clazz, 
List<VariableElement> fields) {
+    private void validatePolymorphicConfigInstance(ClassWrapper classWrapper) {
         checkIncompatibleClassAnnotations(
-                clazz,
+                classWrapper.clazz(),
                 PolymorphicConfigInstance.class,
                 
incompatibleSchemaClassAnnotations(PolymorphicConfigInstance.class)
         );
 
-        checkNotContainsPolymorphicIdField(clazz, 
PolymorphicConfigInstance.class, fields);
+        checkNotContainsPolymorphicIdField(classWrapper, 
PolymorphicConfigInstance.class);
 
-        String id = 
clazz.getAnnotation(PolymorphicConfigInstance.class).value();
+        String id = 
classWrapper.getAnnotation(PolymorphicConfigInstance.class).value();
 
         if (id == null || id.isBlank()) {
             throw new ConfigurationProcessorException(String.format(
                     EMPTY_FIELD_ERROR_FORMAT,
                     simpleName(PolymorphicConfigInstance.class) + ".id()",
-                    clazz.getQualifiedName()
+                    classWrapper.clazz().getQualifiedName()
             ));
         }
 
-        checkExistSuperClass(clazz, PolymorphicConfigInstance.class);
+        checkExistSuperClass(classWrapper.clazz(), 
PolymorphicConfigInstance.class);
 
-        TypeElement superClazz = superClass(clazz);
+        ClassWrapper superClassWrapper = classWrapper.requiredSuperClass();
 
-        checkSuperclassContainAnyAnnotation(clazz, superClazz, 
PolymorphicConfig.class);
+        checkSuperclassContainAnyAnnotation(classWrapper.clazz(), 
superClassWrapper.clazz(), PolymorphicConfig.class);
 
-        checkNoConflictFieldNames(clazz, superClazz, fields, 
fields(superClazz));
+        checkNoConflictFieldNames(classWrapper, superClassWrapper);
     }
 
-    /** {@inheritDoc} */
     @Override
     public Set<String> getSupportedAnnotationTypes() {
-        return 
supportedAnnotationTypes().stream().map(Class::getCanonicalName).collect(toSet());
+        return 
TOP_LEVEL_ANNOTATIONS.stream().map(Class::getCanonicalName).collect(toSet());
     }
 
-    /** {@inheritDoc} */
     @Override
     public SourceVersion getSupportedSourceVersion() {
         return SourceVersion.latest();
     }
 
-    /**
-     * Returns immutable set of annotation types supported by this processor.
-     */
-    private Set<Class<? extends Annotation>> supportedAnnotationTypes() {
-        return Set.of(
-                Config.class,
-                ConfigurationRoot.class,
-                ConfigurationExtension.class,
-                PolymorphicConfig.class,
-                PolymorphicConfigInstance.class,
-                AbstractConfiguration.class
-        );
-    }
-
-    /**
-     * Getting a superclass.
-     *
-     * @param clazz Class type.
-     */
-    private TypeElement superClass(TypeElement clazz) {
-        return 
processingEnv.getElementUtils().getTypeElement(clazz.getSuperclass().toString());
-    }
-
     /**
      * Search for duplicate class fields by name.
      *
@@ -901,12 +854,14 @@ public class ConfigurationProcessor extends 
AbstractProcessor {
         assert clazz.getAnnotation(clazzAnnotation) != null : 
clazz.getQualifiedName();
         assert !nullOrEmpty(incompatibleAnnotations);
 
-        Optional<? extends Annotation> incompatible = 
findFirstPresentAnnotation(clazz, incompatibleAnnotations);
+        Optional<Class<? extends Annotation>> incompatible = 
Arrays.stream(incompatibleAnnotations)
+                .filter(a -> clazz.getAnnotation(a) != null)
+                .findAny();
 
         if (incompatible.isPresent()) {
             throw new ConfigurationProcessorException(String.format(
                     "Class with %s is not allowed with %s: %s",
-                    simpleName(incompatible.get().annotationType()),
+                    simpleName(incompatible.get()),
                     simpleName(clazzAnnotation),
                     clazz.getQualifiedName()
             ));
@@ -954,24 +909,20 @@ public class ConfigurationProcessor extends 
AbstractProcessor {
     /**
      * Checks that the class does not have a field with {@link PolymorphicId}.
      *
-     * @param clazz Class type.
-     * @param clazzAnnotation Class annotation.
-     * @param clazzfields Class fields.
      * @throws ConfigurationProcessorException If the class has a field with 
{@link PolymorphicId}.
      */
     private void checkNotContainsPolymorphicIdField(
-            TypeElement clazz,
-            Class<? extends Annotation> clazzAnnotation,
-            List<VariableElement> clazzfields
+            ClassWrapper classWrapper,
+            Class<? extends Annotation> clazzAnnotation
     ) {
-        assert clazz.getAnnotation(clazzAnnotation) != null : 
clazz.getQualifiedName();
+        assert classWrapper.getAnnotation(clazzAnnotation) != null : 
classWrapper.clazz().getQualifiedName();
 
-        if (!collectFieldsWithAnnotation(clazzfields, 
PolymorphicId.class).isEmpty()) {
+        if (!classWrapper.fieldsAnnotatedWith(PolymorphicId.class).isEmpty()) {
             throw new ConfigurationProcessorException(String.format(
                     "Class with %s cannot have a field with %s: %s",
                     simpleName(clazzAnnotation),
                     simpleName(PolymorphicId.class),
-                    clazz.getQualifiedName()
+                    classWrapper.clazz().getQualifiedName()
             ));
         }
     }
@@ -979,25 +930,19 @@ public class ConfigurationProcessor extends 
AbstractProcessor {
     /**
      * Checks that there is no conflict of field names between classes.
      *
-     * @param clazz0 First class type.
-     * @param clazz1 Second class type.
-     * @param clazzFields0 First class fields.
-     * @param clazzFields1 Second class fields.
      * @throws ConfigurationProcessorException If there is a conflict of field 
names between classes.
      */
     private void checkNoConflictFieldNames(
-            TypeElement clazz0,
-            TypeElement clazz1,
-            List<VariableElement> clazzFields0,
-            List<VariableElement> clazzFields1
+            ClassWrapper classWrapper0,
+            ClassWrapper classWrapper1
     ) {
-        Collection<Name> duplicateFieldNames = findDuplicates(clazzFields0, 
clazzFields1);
+        Collection<Name> duplicateFieldNames = 
findDuplicates(classWrapper0.fields(), classWrapper1.fields());
 
         if (!duplicateFieldNames.isEmpty()) {
             throw new ConfigurationProcessorException(String.format(
                     "Duplicate field names are not allowed [class=%s, 
superClass=%s, fields=%s]",
-                    clazz0.getQualifiedName(),
-                    clazz1.getQualifiedName(),
+                    classWrapper0.clazz().getQualifiedName(),
+                    classWrapper1.clazz().getQualifiedName(),
                     duplicateFieldNames
             ));
         }
@@ -1029,12 +974,10 @@ public class ConfigurationProcessor extends 
AbstractProcessor {
     /**
      * Validation of class fields with {@link InjectedName} if present.
      *
-     * @param clazz Class type.
-     * @param fields Class fields.
      * @throws ConfigurationProcessorException If the class validation fails.
      */
-    private void validateInjectedNameFields(TypeElement clazz, 
List<VariableElement> fields) {
-        List<VariableElement> injectedNameFields = 
collectFieldsWithAnnotation(fields, InjectedName.class);
+    private void validateInjectedNameFields(ClassWrapper classWrapper) {
+        List<VariableElement> injectedNameFields = 
classWrapper.fieldsAnnotatedWith(InjectedName.class);
 
         if (injectedNameFields.isEmpty()) {
             return;
@@ -1043,7 +986,7 @@ public class ConfigurationProcessor extends 
AbstractProcessor {
         if (injectedNameFields.size() > 1) {
             throw new ConfigurationProcessorException(String.format(
                     "%s contains more than one field with %s",
-                    clazz.getQualifiedName(),
+                    classWrapper.clazz().getQualifiedName(),
                     simpleName(InjectedName.class)
             ));
         }
@@ -1054,7 +997,7 @@ public class ConfigurationProcessor extends 
AbstractProcessor {
             throw new ConfigurationProcessorException(String.format(
                     FIELD_MUST_BE_SPECIFIC_CLASS_ERROR_FORMAT,
                     simpleName(InjectedName.class),
-                    clazz.getQualifiedName(),
+                    classWrapper.clazz().getQualifiedName(),
                     injectedNameField.getSimpleName(),
                     String.class.getSimpleName()
             ));
@@ -1064,31 +1007,30 @@ public class ConfigurationProcessor extends 
AbstractProcessor {
         if (injectedNameField.getAnnotationMirrors().size() > 1) {
             throw new ConfigurationProcessorException(String.format(
                     "%s.%s must contain only one %s",
-                    clazz.getQualifiedName(),
+                    classWrapper.clazz().getQualifiedName(),
                     injectedNameField.getSimpleName(),
                     simpleName(InjectedName.class)
             ));
         }
 
-        findFirstPresentAnnotation(clazz, Config.class, 
PolymorphicConfig.class, AbstractConfiguration.class)
-                .orElseThrow(() -> new 
ConfigurationProcessorException(String.format(
-                        "%s %s.%s can only be present in a class annotated 
with %s",
-                        simpleName(InjectedName.class),
-                        clazz.getQualifiedName(),
-                        injectedNameField.getSimpleName(),
-                        joinSimpleName(" or ", Config.class, 
PolymorphicConfig.class, AbstractConfiguration.class)
-                )));
+        if (!containsAnyAnnotation(classWrapper.clazz(), Config.class, 
PolymorphicConfig.class, AbstractConfiguration.class)) {
+            throw new ConfigurationProcessorException(String.format(
+                    "%s %s.%s can only be present in a class annotated with 
%s",
+                    simpleName(InjectedName.class),
+                    classWrapper.clazz().getQualifiedName(),
+                    injectedNameField.getSimpleName(),
+                    joinSimpleName(" or ", Config.class, 
PolymorphicConfig.class, AbstractConfiguration.class)
+            ));
+        }
     }
 
     /**
      * Validation of class fields with {@link Name} if present.
      *
-     * @param clazz Class type.
-     * @param fields Class fields.
      * @throws ConfigurationProcessorException If the class validation fails.
      */
-    private void validateNameFields(TypeElement clazz, List<VariableElement> 
fields) {
-        List<VariableElement> nameFields = collectFieldsWithAnnotation(fields, 
org.apache.ignite.configuration.annotation.Name.class);
+    private void validateNameFields(ClassWrapper classWrapper) {
+        List<VariableElement> nameFields = 
classWrapper.fieldsAnnotatedWith(org.apache.ignite.configuration.annotation.Name.class);
 
         if (nameFields.isEmpty()) {
             return;
@@ -1100,7 +1042,7 @@ public class ConfigurationProcessor extends 
AbstractProcessor {
                         "%s annotation can only be used with %s: %s.%s",
                         
simpleName(org.apache.ignite.configuration.annotation.Name.class),
                         simpleName(ConfigValue.class),
-                        clazz.getQualifiedName(),
+                        classWrapper.clazz().getQualifiedName(),
                         nameField.getSimpleName()
                 ));
             }
@@ -1117,18 +1059,20 @@ public class ConfigurationProcessor extends 
AbstractProcessor {
     private void checkMissingNameForInjectedName(VariableElement field) {
         TypeElement fieldType = (TypeElement) 
processingEnv.getTypeUtils().asElement(field.asType());
 
-        TypeElement superClassFieldType = superClass(fieldType);
+        var fieldClassWrapper = new ClassWrapper(processingEnv, fieldType);
+
+        ClassWrapper fieldSuperClassWrapper = fieldClassWrapper.superClass();
 
         List<VariableElement> fields;
 
-        if (!isClass(superClassFieldType.asType(), Object.class)
-                && 
superClassFieldType.getAnnotation(AbstractConfiguration.class) != null) {
+        if (fieldSuperClassWrapper != null
+                && 
fieldSuperClassWrapper.getAnnotation(AbstractConfiguration.class) != null) {
             fields = concat(
-                    collectFieldsWithAnnotation(fields(fieldType), 
InjectedName.class),
-                    collectFieldsWithAnnotation(fields(superClassFieldType), 
InjectedName.class)
+                    fieldClassWrapper.fieldsAnnotatedWith(InjectedName.class),
+                    
fieldSuperClassWrapper.fieldsAnnotatedWith(InjectedName.class)
             );
         } else {
-            fields = collectFieldsWithAnnotation(fields(fieldType), 
InjectedName.class);
+            fields = fieldClassWrapper.fieldsAnnotatedWith(InjectedName.class);
         }
 
         if (!fields.isEmpty() && 
field.getAnnotation(org.apache.ignite.configuration.annotation.Name.class) == 
null) {
@@ -1144,64 +1088,58 @@ public class ConfigurationProcessor extends 
AbstractProcessor {
     /**
      * Checks configuration schema with {@link AbstractConfiguration}.
      *
-     * @param clazz Type element under validation.
-     * @param fields Non-static fields of the class under validation.
      * @throws ConfigurationProcessorException If validation fails.
      */
-    private void validateAbstractConfiguration(TypeElement clazz, 
List<VariableElement> fields) throws ConfigurationProcessorException {
+    private void validateAbstractConfiguration(ClassWrapper classWrapper) 
throws ConfigurationProcessorException {
         checkIncompatibleClassAnnotations(
-                clazz,
+                classWrapper.clazz(),
                 AbstractConfiguration.class,
                 incompatibleSchemaClassAnnotations(AbstractConfiguration.class)
         );
 
-        checkNotExistSuperClass(clazz, AbstractConfiguration.class);
+        checkNotExistSuperClass(classWrapper.clazz(), 
AbstractConfiguration.class);
 
-        checkNotContainsPolymorphicIdField(clazz, AbstractConfiguration.class, 
fields);
+        checkNotContainsPolymorphicIdField(classWrapper, 
AbstractConfiguration.class);
     }
 
     /**
      * Checks configuration schema with {@link ConfigurationRoot}.
      *
-     * @param clazz Type element under validation.
-     * @param fields Non-static fields of the class under validation.
      * @throws ConfigurationProcessorException If validation fails.
      */
-    private void validateConfigurationRoot(TypeElement clazz, 
List<VariableElement> fields) throws ConfigurationProcessorException {
+    private void validateConfigurationRoot(ClassWrapper classWrapper) throws 
ConfigurationProcessorException {
         checkIncompatibleClassAnnotations(
-                clazz,
+                classWrapper.clazz(),
                 ConfigurationRoot.class,
                 incompatibleSchemaClassAnnotations(ConfigurationRoot.class)
         );
 
-        checkNotContainsPolymorphicIdField(clazz, ConfigurationRoot.class, 
fields);
+        checkNotContainsPolymorphicIdField(classWrapper, 
ConfigurationRoot.class);
 
-        TypeElement superClazz = superClass(clazz);
+        ClassWrapper superClassWrapper = classWrapper.superClass();
 
-        if (!isClass(superClazz.asType(), Object.class)) {
-            checkSuperclassContainAnyAnnotation(clazz, superClazz, 
AbstractConfiguration.class);
+        if (superClassWrapper != null) {
+            checkSuperclassContainAnyAnnotation(classWrapper.clazz(), 
superClassWrapper.clazz(), AbstractConfiguration.class);
 
-            List<VariableElement> superClazzFields = fields(superClazz);
-
-            checkNoConflictFieldNames(clazz, superClazz, fields, 
superClazzFields);
+            checkNoConflictFieldNames(classWrapper, superClassWrapper);
 
             String invalidFieldInSuperClassFormat = "Field with %s in 
superclass are not allowed [class=%s, superClass=%s]";
 
-            if (!collectFieldsWithAnnotation(superClazzFields, 
InjectedName.class).isEmpty()) {
+            if 
(!superClassWrapper.fieldsAnnotatedWith(InjectedName.class).isEmpty()) {
                 throw new ConfigurationProcessorException(String.format(
                         invalidFieldInSuperClassFormat,
                         simpleName(InjectedName.class),
-                        clazz.getQualifiedName(),
-                        superClazz.getQualifiedName()
+                        classWrapper.clazz().getQualifiedName(),
+                        superClassWrapper.clazz().getQualifiedName()
                 ));
             }
 
-            if (!collectFieldsWithAnnotation(superClazzFields, 
InternalId.class).isEmpty()) {
+            if 
(!superClassWrapper.fieldsAnnotatedWith(InternalId.class).isEmpty()) {
                 throw new ConfigurationProcessorException(String.format(
                         invalidFieldInSuperClassFormat,
                         simpleName(InternalId.class),
-                        clazz.getQualifiedName(),
-                        superClazz.getQualifiedName()
+                        classWrapper.clazz().getQualifiedName(),
+                        superClassWrapper.clazz().getQualifiedName()
                 ));
             }
         }
@@ -1210,47 +1148,43 @@ public class ConfigurationProcessor extends 
AbstractProcessor {
     /**
      * Checks configuration schema with {@link Config}.
      *
-     * @param clazz Type element under validation.
-     * @param fields Non-static fields of the class under validation.
      * @throws ConfigurationProcessorException If validation fails.
      */
-    private void validateConfig(TypeElement clazz, List<VariableElement> 
fields) throws ConfigurationProcessorException {
+    private void validateConfig(ClassWrapper classWrapper) throws 
ConfigurationProcessorException {
         checkIncompatibleClassAnnotations(
-                clazz,
+                classWrapper.clazz(),
                 Config.class,
                 incompatibleSchemaClassAnnotations(Config.class)
         );
 
-        checkNotContainsPolymorphicIdField(clazz, Config.class, fields);
-
-        TypeElement superClazz = superClass(clazz);
+        checkNotContainsPolymorphicIdField(classWrapper, Config.class);
 
-        if (!isClass(superClazz.asType(), Object.class)) {
-            checkSuperclassContainAnyAnnotation(clazz, superClazz, 
AbstractConfiguration.class);
+        ClassWrapper superClassWrapper = classWrapper.superClass();
 
-            List<VariableElement> superClazzFields = fields(superClazz);
+        if (superClassWrapper != null) {
+            checkSuperclassContainAnyAnnotation(classWrapper.clazz(), 
superClassWrapper.clazz(), AbstractConfiguration.class);
 
-            checkNoConflictFieldNames(clazz, superClazz, fields, 
superClazzFields);
+            checkNoConflictFieldNames(classWrapper, superClassWrapper);
 
             String fieldAlreadyPresentInSuperClassFormat = "Field with %s is 
already present in the superclass [class=%s, superClass=%s]";
 
-            if (!collectFieldsWithAnnotation(superClazzFields, 
InjectedName.class).isEmpty()
-                    && !collectFieldsWithAnnotation(fields, 
InjectedName.class).isEmpty()) {
+            if 
(!superClassWrapper.fieldsAnnotatedWith(InjectedName.class).isEmpty()
+                    && 
!classWrapper.fieldsAnnotatedWith(InjectedName.class).isEmpty()) {
                 throw new ConfigurationProcessorException(String.format(
                         fieldAlreadyPresentInSuperClassFormat,
                         simpleName(InjectedName.class),
-                        clazz.getQualifiedName(),
-                        superClazz.getQualifiedName()
+                        classWrapper.clazz().getQualifiedName(),
+                        superClassWrapper.clazz().getQualifiedName()
                 ));
             }
 
-            if (!collectFieldsWithAnnotation(superClazzFields, 
InternalId.class).isEmpty()
-                    && !collectFieldsWithAnnotation(fields, 
InternalId.class).isEmpty()) {
+            if 
(!superClassWrapper.fieldsAnnotatedWith(InternalId.class).isEmpty()
+                    && 
!classWrapper.fieldsAnnotatedWith(InternalId.class).isEmpty()) {
                 throw new ConfigurationProcessorException(String.format(
                         fieldAlreadyPresentInSuperClassFormat,
                         simpleName(InternalId.class),
-                        clazz.getQualifiedName(),
-                        superClazz.getQualifiedName()
+                        classWrapper.clazz().getQualifiedName(),
+                        superClassWrapper.clazz().getQualifiedName()
                 ));
             }
         }
@@ -1258,6 +1192,6 @@ public class ConfigurationProcessor extends 
AbstractProcessor {
 
     @SafeVarargs
     private Class<? extends Annotation>[] 
incompatibleSchemaClassAnnotations(Class<? extends Annotation>... 
compatibleAnnotations) {
-        return difference(supportedAnnotationTypes(), 
Set.of(compatibleAnnotations)).toArray(Class[]::new);
+        return difference(TOP_LEVEL_ANNOTATIONS, 
Set.of(compatibleAnnotations)).toArray(Class[]::new);
     }
 }
diff --git 
a/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/internal/configuration/processor/ConfigurationProcessorUtils.java
 
b/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/internal/configuration/processor/ConfigurationProcessorUtils.java
index 5061557ed1..5cf5a6c7e1 100644
--- 
a/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/internal/configuration/processor/ConfigurationProcessorUtils.java
+++ 
b/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/internal/configuration/processor/ConfigurationProcessorUtils.java
@@ -18,17 +18,19 @@
 package org.apache.ignite.internal.configuration.processor;
 
 import static java.util.stream.Collectors.joining;
-import static java.util.stream.Collectors.toList;
 
 import com.squareup.javapoet.ClassName;
 import java.lang.annotation.Annotation;
-import java.util.Collection;
+import java.util.Arrays;
 import java.util.List;
-import java.util.Objects;
-import java.util.Optional;
+import java.util.UUID;
 import java.util.stream.Stream;
+import javax.annotation.processing.ProcessingEnvironment;
 import javax.lang.model.element.Element;
-import javax.lang.model.element.VariableElement;
+import javax.lang.model.type.ArrayType;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+import org.apache.ignite.configuration.annotation.Value;
 
 /**
  * Annotation processing utilities.
@@ -91,37 +93,53 @@ public class ConfigurationProcessorUtils {
     }
 
     /**
-     * Returns the first annotation found for the given element.
-     *
-     * @param element Element.
-     * @param annotationClasses Annotation classes that will be searched for 
the element.
+     * Returns {@code true} if any of the given annotations are present on any 
of the given elements.
      */
     @SafeVarargs
-    public static Optional<? extends Annotation> findFirstPresentAnnotation(
-            Element element,
-            Class<? extends Annotation>... annotationClasses
-    ) {
-        return 
Stream.of(annotationClasses).map(element::getAnnotation).filter(Objects::nonNull).findFirst();
+    public static boolean containsAnyAnnotation(List<? extends Element> 
elements, Class<? extends Annotation>... annotations) {
+        return elements.stream().anyMatch(e -> containsAnyAnnotation(e, 
annotations));
     }
 
     /**
      * Returns {@code true} if any of the given annotations are present on the 
given element.
      */
     @SafeVarargs
-    public static boolean containsAnyAnnotation(Element element, Class<? 
extends Annotation>... annotationClasses) {
-        return findFirstPresentAnnotation(element, 
annotationClasses).isPresent();
+    public static boolean containsAnyAnnotation(Element element, Class<? 
extends Annotation>... annotations) {
+        return Arrays.stream(annotations).anyMatch(a -> 
element.getAnnotation(a) != null);
     }
 
     /**
-     * Collect fields with annotation.
+     * Checks that the type of the field with {@link Value} is valid: 
primitive, {@link String}, or {@link UUID} (or an array of one of
+     * these).
      *
-     * @param fields Fields.
-     * @param annotationClass Annotation class.
+     * @param type Field type with {@link Value}.
+     * @return {@code True} if the field type is valid.
+     */
+    public static boolean 
isValidValueAnnotationFieldType(ProcessingEnvironment processingEnvironment, 
TypeMirror type) {
+        if (type.getKind() == TypeKind.ARRAY) {
+            type = ((ArrayType) type).getComponentType();
+        }
+
+        if (type.getKind().isPrimitive()) {
+            return true;
+        }
+
+        return sameType(processingEnvironment, type, String.class) || 
sameType(processingEnvironment, type, UUID.class);
+    }
+
+    /**
+     * Returns {@code true} if the given types are the same type.
+     *
+     * @param type1 first type (represented by a mirror)
+     * @param type2 second type (represented by a {@code Class})
+     * @return {@code true} if both types represent the same type, {@code 
false} otherwise.
      */
-    public static List<VariableElement> collectFieldsWithAnnotation(
-            Collection<VariableElement> fields,
-            Class<? extends Annotation> annotationClass
-    ) {
-        return fields.stream().filter(f -> f.getAnnotation(annotationClass) != 
null).collect(toList());
+    public static boolean sameType(ProcessingEnvironment 
processingEnvironment, TypeMirror type1, Class<?> type2) {
+        TypeMirror classType = processingEnvironment
+                .getElementUtils()
+                .getTypeElement(type2.getCanonicalName())
+                .asType();
+
+        return processingEnvironment.getTypeUtils().isSameType(classType, 
type1);
     }
 }
diff --git 
a/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/internal/configuration/processor/ConfigurationValidationException.java
 
b/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/internal/configuration/processor/ConfigurationValidationException.java
new file mode 100644
index 0000000000..d0b9d5a0eb
--- /dev/null
+++ 
b/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/internal/configuration/processor/ConfigurationValidationException.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.configuration.processor;
+
+/**
+ * Exception thrown when a configuration class does not pass validation.
+ */
+public class ConfigurationValidationException extends 
ConfigurationProcessorException {
+    public ConfigurationValidationException(ClassWrapper classWrapper, String 
message) {
+        super(String.format("Validation issue when processing class %s: %s", 
classWrapper, message));
+    }
+}
diff --git 
a/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/internal/configuration/processor/validators/InjectedValueValidator.java
 
b/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/internal/configuration/processor/validation/InjectedValueValidator.java
similarity index 87%
rename from 
modules/configuration-annotation-processor/src/main/java/org/apache/ignite/internal/configuration/processor/validators/InjectedValueValidator.java
rename to 
modules/configuration-annotation-processor/src/main/java/org/apache/ignite/internal/configuration/processor/validation/InjectedValueValidator.java
index 7963ff8124..defebb1dc3 100644
--- 
a/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/internal/configuration/processor/validators/InjectedValueValidator.java
+++ 
b/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/internal/configuration/processor/validation/InjectedValueValidator.java
@@ -15,22 +15,21 @@
  * limitations under the License.
  */
 
-package org.apache.ignite.internal.configuration.processor.validators;
+package org.apache.ignite.internal.configuration.processor.validation;
 
-import static 
org.apache.ignite.internal.configuration.processor.ConfigurationProcessorUtils.collectFieldsWithAnnotation;
 import static 
org.apache.ignite.internal.configuration.processor.ConfigurationProcessorUtils.simpleName;
 import static org.apache.ignite.internal.util.CollectionUtils.concat;
 
 import java.util.List;
 import java.util.UUID;
 import javax.annotation.processing.ProcessingEnvironment;
-import javax.lang.model.element.TypeElement;
 import javax.lang.model.element.VariableElement;
 import javax.lang.model.type.ArrayType;
 import javax.lang.model.type.TypeKind;
 import javax.lang.model.type.TypeMirror;
 import org.apache.ignite.configuration.annotation.InjectedValue;
 import org.apache.ignite.configuration.annotation.Value;
+import org.apache.ignite.internal.configuration.processor.ClassWrapper;
 import 
org.apache.ignite.internal.configuration.processor.ConfigurationProcessorException;
 
 /**
@@ -51,20 +50,20 @@ public class InjectedValueValidator {
      *     <li>There is only a single InjectedValue field in the schema 
(including {@link Value} fields).</li>
      * </ol>
      */
-    public void validate(TypeElement clazz, List<VariableElement> fields) {
-        List<VariableElement> injectedValueFields = 
collectFieldsWithAnnotation(fields, InjectedValue.class);
+    public void validate(ClassWrapper classWrapper) {
+        List<VariableElement> injectedValueFields = 
classWrapper.fieldsAnnotatedWith(InjectedValue.class);
 
         if (injectedValueFields.isEmpty()) {
             return;
         }
 
-        List<VariableElement> valueFields = 
collectFieldsWithAnnotation(fields, Value.class);
+        List<VariableElement> valueFields = 
classWrapper.fieldsAnnotatedWith(Value.class);
 
         if (injectedValueFields.size() > 1 || !valueFields.isEmpty()) {
             throw new ConfigurationProcessorException(String.format(
                     "Field marked as %s must be the only \"value\" field in 
the schema %s, found: %s",
                     simpleName(InjectedValue.class),
-                    clazz.getQualifiedName(),
+                    classWrapper.clazz().getQualifiedName(),
                     concat(injectedValueFields, valueFields)
             ));
         }
@@ -76,7 +75,7 @@ public class InjectedValueValidator {
             throw new ConfigurationProcessorException(String.format(
                     "%s.%s field must have one of the following types: "
                             + "boolean, int, long, double, String, UUID or an 
array of aforementioned type.",
-                    clazz.getQualifiedName(),
+                    classWrapper.clazz().getQualifiedName(),
                     injectedValueField.getSimpleName()
             ));
         }

Reply via email to