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 94cf6862a48 IGNITE-27772 Prohibit using null values as configuration 
default (#7702)
94cf6862a48 is described below

commit 94cf6862a48671e01f8c4ad3598578f8efc701c9
Author: Alexander Polovtcev <[email protected]>
AuthorDate: Wed Mar 4 15:40:52 2026 +0200

    IGNITE-27772 Prohibit using null values as configuration default (#7702)
---
 .../processor/ItConfigurationProcessorTest.java    | 11 ++++++++
 .../NullDefaultValueConfigurationSchema.java       | 31 ++++++++++++++++++++++
 .../validation/MiscellaneousIssuesValidator.java   | 26 +++++++++++++++++-
 .../ignite/configuration/annotation/Value.java     |  7 +++--
 4 files changed, 72 insertions(+), 3 deletions(-)

diff --git 
a/modules/configuration-annotation-processor/src/integrationTest/java/org/apache/ignite/internal/configuration/processor/ItConfigurationProcessorTest.java
 
b/modules/configuration-annotation-processor/src/integrationTest/java/org/apache/ignite/internal/configuration/processor/ItConfigurationProcessorTest.java
index beeea43c20e..ba53448573b 100644
--- 
a/modules/configuration-annotation-processor/src/integrationTest/java/org/apache/ignite/internal/configuration/processor/ItConfigurationProcessorTest.java
+++ 
b/modules/configuration-annotation-processor/src/integrationTest/java/org/apache/ignite/internal/configuration/processor/ItConfigurationProcessorTest.java
@@ -275,6 +275,17 @@ public class ItConfigurationProcessorTest extends 
AbstractProcessorTest {
         }
     }
 
+    @Test
+    void testValueFieldWithNullDefaultValue() {
+        String packageName = 
"org.apache.ignite.internal.configuration.processor";
+
+        assertThrowsEx(
+                IllegalStateException.class,
+                () -> batchCompile(packageName, 
"NullDefaultValueConfigurationSchema"),
+                "Field 'str' is marked with 'hasDefault = true' but the 
default value is null."
+        );
+    }
+
     @Test
     void wrongSchemaPostfix() {
         String packageName = 
"org.apache.ignite.internal.configuration.processor";
diff --git 
a/modules/configuration-annotation-processor/src/integrationTest/resources/org/apache/ignite/internal/configuration/processor/NullDefaultValueConfigurationSchema.java
 
b/modules/configuration-annotation-processor/src/integrationTest/resources/org/apache/ignite/internal/configuration/processor/NullDefaultValueConfigurationSchema.java
new file mode 100644
index 00000000000..1e567a47c94
--- /dev/null
+++ 
b/modules/configuration-annotation-processor/src/integrationTest/resources/org/apache/ignite/internal/configuration/processor/NullDefaultValueConfigurationSchema.java
@@ -0,0 +1,31 @@
+/*
+ * 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 org.apache.ignite.configuration.annotation.ConfigurationRoot;
+import org.apache.ignite.configuration.annotation.Value;
+
+/**
+ * Schema with a {@code @Value(hasDefault = true)} field that has a {@code 
null} default value.
+ * This is expected to fail compilation.
+ */
+@ConfigurationRoot(rootName = "nullDefaultValue")
+public class NullDefaultValueConfigurationSchema {
+    @Value(hasDefault = true)
+    public String str = null;
+}
diff --git 
a/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/internal/configuration/processor/validation/MiscellaneousIssuesValidator.java
 
b/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/internal/configuration/processor/validation/MiscellaneousIssuesValidator.java
index 54e83fce4c6..48b5fd34bf4 100644
--- 
a/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/internal/configuration/processor/validation/MiscellaneousIssuesValidator.java
+++ 
b/modules/configuration-annotation-processor/src/main/java/org/apache/ignite/internal/configuration/processor/validation/MiscellaneousIssuesValidator.java
@@ -17,11 +17,15 @@
 
 package org.apache.ignite.internal.configuration.processor.validation;
 
+import static com.sun.source.tree.Tree.Kind.NULL_LITERAL;
 import static javax.lang.model.element.Modifier.PUBLIC;
 import static 
org.apache.ignite.internal.configuration.processor.ConfigurationProcessor.CONFIGURATION_SCHEMA_POSTFIX;
 import static 
org.apache.ignite.internal.configuration.processor.ConfigurationProcessorUtils.containsAnyAnnotation;
 import static 
org.apache.ignite.internal.configuration.processor.ConfigurationProcessorUtils.simpleName;
 
+import com.sun.source.tree.ExpressionTree;
+import com.sun.source.tree.VariableTree;
+import com.sun.source.util.Trees;
 import java.util.UUID;
 import javax.annotation.processing.ProcessingEnvironment;
 import javax.lang.model.element.VariableElement;
@@ -78,9 +82,19 @@ public class MiscellaneousIssuesValidator extends Validator {
                 ));
             }
 
-            if (field.getAnnotation(Value.class) != null) {
+            Value valueAnnotation = field.getAnnotation(Value.class);
+
+            if (valueAnnotation != null) {
                 // Must be a primitive or an array of the primitives 
(including java.lang.String, java.util.UUID).
                 assertValidValueFieldType(classWrapper, field);
+
+                // Fields with "hasDefault = true" must not be initialized 
with null.
+                if (valueAnnotation.hasDefault() && 
isInitializedWithNull(field)) {
+                    throw new ConfigurationValidationException(classWrapper, 
String.format(
+                            "Field '%s' is marked with 'hasDefault = true' but 
the default value is null.",
+                            field.getSimpleName()
+                    ));
+                }
             }
 
             if (field.getAnnotation(PolymorphicId.class) != null) {
@@ -105,4 +119,14 @@ public class MiscellaneousIssuesValidator extends 
Validator {
             }
         }
     }
+
+    private boolean isInitializedWithNull(VariableElement field) {
+        Trees trees = Trees.instance(processingEnvironment);
+
+        var variableTree = (VariableTree) trees.getTree(field);
+
+        ExpressionTree initializer = variableTree.getInitializer();
+
+        return initializer != null && initializer.getKind() == NULL_LITERAL;
+    }
 }
diff --git 
a/modules/configuration-api/src/main/java/org/apache/ignite/configuration/annotation/Value.java
 
b/modules/configuration-api/src/main/java/org/apache/ignite/configuration/annotation/Value.java
index ea0be22615e..deaaf240d4c 100644
--- 
a/modules/configuration-api/src/main/java/org/apache/ignite/configuration/annotation/Value.java
+++ 
b/modules/configuration-api/src/main/java/org/apache/ignite/configuration/annotation/Value.java
@@ -44,8 +44,11 @@ import java.util.UUID;
 @Documented
 public @interface Value {
     /**
-     * Indicates that the current configuration value has a default value. 
Value itself is derived from the instantiated object of a
-     * corresponding schema type. This means that the default is not 
necessarily a constant value.
+     * Indicates that the current configuration value has a default value. The 
value itself is derived from the instantiated object of the
+     * corresponding schema type, meaning the default is not necessarily a 
constant value. It can also be provided dynamically via
+     * {@link 
org.apache.ignite.configuration.ConfigurationModule#patchConfigurationWithDynamicDefaults}.
+     *
+     * <p>When set to {@code true}, the field initializer must not be an 
explicit {@code null} literal.
      *
      * @return {@code hasDefault} flag value.
      */

Reply via email to