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

pvillard31 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git


The following commit(s) were added to refs/heads/main by this push:
     new c7fa678a12c NIFI-16324 Include property defaults during Connector 
Verify Configuration (#11651)
c7fa678a12c is described below

commit c7fa678a12c0a9e5c5774bb2590c85bdc76162bc
Author: Mark Payne <[email protected]>
AuthorDate: Wed Sep 9 05:57:14 2026 -0400

    NIFI-16324 Include property defaults during Connector Verify Configuration 
(#11651)
---
 .../connector/StandardConnectorNode.java           | 34 ++++++++++++++++-
 .../connector/TestStandardConnectorNode.java       | 43 ++++++++++++++++++++++
 2 files changed, 75 insertions(+), 2 deletions(-)

diff --git 
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/components/connector/StandardConnectorNode.java
 
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/components/connector/StandardConnectorNode.java
index 06b87484e8e..6a883dd710d 100644
--- 
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/components/connector/StandardConnectorNode.java
+++ 
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/components/connector/StandardConnectorNode.java
@@ -1669,6 +1669,7 @@ public class StandardConnectorNode implements 
ConnectorNode, GroupedComponent {
 
         final Map<String, String> resolvedProperties = new HashMap<>();
         final Map<String, ConnectorPropertyDescriptor> descriptorLookup = 
buildPropertyDescriptorLookup(configurationStep);
+        final StepConfiguration effectiveConfiguration = 
createEffectiveStepConfiguration(configurationStep.getName(), 
configurationOverrides);
 
         try {
             // Secret References can be expensive to lookup so we don't want 
to call getSecret() for each one. Instead, we
@@ -1680,7 +1681,7 @@ public class StandardConnectorNode implements 
ConnectorNode, GroupedComponent {
                 .filter(entry -> !isEmptySecretReference((SecretReference) 
entry.getValue()))
                 .filter(entry -> {
                     final ConnectorPropertyDescriptor descriptor = 
descriptorLookup.get(entry.getKey());
-                    return descriptor == null || 
isPropertyDependencySatisfied(descriptor, descriptorLookup::get, 
configurationOverrides);
+                    return descriptor == null || 
isPropertyDependencySatisfied(descriptor, descriptorLookup::get, 
effectiveConfiguration);
                 })
                 .map(entry -> (SecretReference) entry.getValue())
                 .collect(Collectors.toSet());
@@ -1703,7 +1704,7 @@ public class StandardConnectorNode implements 
ConnectorNode, GroupedComponent {
                 }
 
                 final ConnectorPropertyDescriptor descriptor = 
descriptorLookup.get(propertyName);
-                if (descriptor != null && 
!isPropertyDependencySatisfied(descriptor, descriptorLookup::get, 
configurationOverrides)) {
+                if (descriptor != null && 
!isPropertyDependencySatisfied(descriptor, descriptorLookup::get, 
effectiveConfiguration)) {
                     // Omit values for properties that are not applicable so 
merged configuration does not retain stale overrides
                     // (createWithOverrides removes keys when the override 
value is null).
                     resolvedProperties.put(propertyName, null);
@@ -1733,6 +1734,14 @@ public class StandardConnectorNode implements 
ConnectorNode, GroupedComponent {
                     invalidAssetRefs.add((AssetReference) valueReference);
                 }
             }
+
+            for (final ConnectorPropertyDescriptor descriptor : 
descriptorLookup.values()) {
+                if (descriptor.getDefaultValue() != null
+                        && 
!effectiveConfiguration.getPropertyValues().containsKey(descriptor.getName())
+                        && isPropertyDependencySatisfied(descriptor, 
descriptorLookup::get, effectiveConfiguration)) {
+                    resolvedProperties.put(descriptor.getName(), 
descriptor.getDefaultValue());
+                }
+            }
         } catch (final IOException ioe) {
             throw new UncheckedIOException("Failed to resolve Secret 
references for " + this, ioe);
         }
@@ -1740,6 +1749,27 @@ public class StandardConnectorNode implements 
ConnectorNode, GroupedComponent {
         return resolvedProperties;
     }
 
+    private StepConfiguration createEffectiveStepConfiguration(final String 
stepName, final StepConfiguration configurationOverrides) {
+        final Map<String, ConnectorValueReference> effectiveProperties = new 
HashMap<>();
+        final NamedStepConfiguration workingStepConfiguration = 
workingFlowContext.getConfigurationContext()
+            .toConnectorConfiguration()
+            .getNamedStepConfiguration(stepName);
+        if (workingStepConfiguration != null) {
+            
effectiveProperties.putAll(workingStepConfiguration.configuration().getPropertyValues());
+        }
+
+        for (final Map.Entry<String, ConnectorValueReference> entry : 
configurationOverrides.getPropertyValues().entrySet()) {
+            final ConnectorValueReference valueReference = entry.getValue();
+            if (valueReference == null || valueReference instanceof final 
StringLiteralValue stringLiteralValue && stringLiteralValue.getValue() == null) 
{
+                effectiveProperties.remove(entry.getKey());
+            } else {
+                effectiveProperties.put(entry.getKey(), valueReference);
+            }
+        }
+
+        return new StepConfiguration(effectiveProperties);
+    }
+
     private static Map<String, ConnectorPropertyDescriptor> 
buildPropertyDescriptorLookup(final ConfigurationStep configurationStep) {
         final Map<String, ConnectorPropertyDescriptor> lookup = new 
HashMap<>();
         for (final ConnectorPropertyGroup propertyGroup : 
configurationStep.getPropertyGroups()) {
diff --git 
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/components/connector/TestStandardConnectorNode.java
 
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/components/connector/TestStandardConnectorNode.java
index f96b2e9af75..d729c888e72 100644
--- 
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/components/connector/TestStandardConnectorNode.java
+++ 
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/components/connector/TestStandardConnectorNode.java
@@ -775,6 +775,28 @@ public class TestStandardConnectorNode {
         assertEquals("The property value is invalid", 
failedResult.getExplanation());
     }
 
+    @Test
+    public void 
testVerifyConfigurationStepIncludesApplicableDefaultsAndExplicitOverrides() 
throws FlowUpdateException {
+        final DefaultValueVerifyingConnector connector = new 
DefaultValueVerifyingConnector();
+        final StandardConnectorNode connectorNode = 
createConnectorNode(connector);
+
+        connectorNode.transitionStateForUpdating();
+        connectorNode.prepareForUpdate();
+        connectorNode.setConfiguration("settings", new 
StepConfiguration(Map.of("Greeting", new StringLiteralValue("Hello"))));
+        final List<ConfigVerificationResult> results = 
connectorNode.verifyConfigurationStep(
+            "settings", new StepConfiguration(Map.of("Greeting", new 
StringLiteralValue("Welcome"))));
+
+        assertEquals(ConfigVerificationResult.Outcome.SUCCESSFUL, 
results.getFirst().getOutcome());
+        assertEquals("Welcome", connector.getVerifiedGreeting());
+        assertEquals("1", connector.getVerifiedRepeatCount());
+
+        connectorNode.setConfiguration("settings", new 
StepConfiguration(Map.of("Repeat Count", new StringLiteralValue("2"))));
+        connectorNode.verifyConfigurationStep("settings", new 
StepConfiguration(Map.of("Greeting", new StringLiteralValue("Hello again"))));
+
+        assertEquals("Hello again", connector.getVerifiedGreeting());
+        assertEquals("2", connector.getVerifiedRepeatCount());
+    }
+
     @Test
     public void 
testVerifyConfigurationStepSkipsSecretReferenceWhenPropertyDependenciesNotMet() 
throws FlowUpdateException {
         // Use a SecretsManager that fails the test if it is consulted. This 
isolates the dependency-skip path: a regression
@@ -1883,6 +1905,27 @@ public class TestStandardConnectorNode {
         }
     }
 
+    private static class DefaultValueVerifyingConnector extends 
DefaultValueConnector {
+        private String verifiedGreeting;
+        private String verifiedRepeatCount;
+
+        @Override
+        public List<ConfigVerificationResult> verifyConfigurationStep(final 
String stepName, final Map<String, String> overrides, final FlowContext 
flowContext) {
+            final ConnectorConfigurationContext configurationContext = 
flowContext.getConfigurationContext().createWithOverrides(stepName, overrides);
+            verifiedGreeting = configurationContext.getProperty(stepName, 
"Greeting").getValue();
+            verifiedRepeatCount = configurationContext.getProperty(stepName, 
"Repeat Count").getValue();
+            return List.of();
+        }
+
+        public String getVerifiedGreeting() {
+            return verifiedGreeting;
+        }
+
+        public String getVerifiedRepeatCount() {
+            return verifiedRepeatCount;
+        }
+    }
+
     private static class DependentDefaultValueConnector extends 
AbstractConnector {
         @Override
         public VersionedExternalFlow getInitialFlow() {

Reply via email to