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