This is an automated email from the ASF dual-hosted git repository.
exceptionfactory 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 c00502adfb NIFI-14935 Improved handling of a Parameter referencing a
Controller Service (#10265)
c00502adfb is described below
commit c00502adfb1c4dbac5ce4ce205e888420e0bb6df
Author: Pierre Villard <[email protected]>
AuthorDate: Sat Sep 6 23:27:44 2025 +0200
NIFI-14935 Improved handling of a Parameter referencing a Controller
Service (#10265)
Signed-off-by: David Handermann <[email protected]>
---
.../flow/mapping/NiFiRegistryFlowMapper.java | 16 +++++-
.../flow/mapping/NiFiRegistryFlowMapperTest.java | 60 ++++++++++++++++++++++
2 files changed, 74 insertions(+), 2 deletions(-)
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/registry/flow/mapping/NiFiRegistryFlowMapper.java
b/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/registry/flow/mapping/NiFiRegistryFlowMapper.java
index 37b7ac6b4f..dba641a9e8 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/registry/flow/mapping/NiFiRegistryFlowMapper.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-framework-components/src/main/java/org/apache/nifi/registry/flow/mapping/NiFiRegistryFlowMapper.java
@@ -925,8 +925,20 @@ public class NiFiRegistryFlowMapper {
} else {
final String referencedVersionServiceId =
referencedControllerServiceData.getFirst().getVersionedServiceId();
final String parameterValue = parameter.getValue();
- final String serviceId =
getId(Optional.ofNullable(referencedVersionServiceId), parameterValue);
- versionedParameter = mapParameter(parameter, serviceId);
+
+ // If a referenced Versioned Service ID is available, use it
directly. Do not attempt to
+ // generate or cache a mapping using a null component
identifier.
+ if (referencedVersionServiceId != null) {
+ versionedParameter = mapParameter(parameter,
referencedVersionServiceId);
+ } else if (parameterValue != null &&
!parameterValue.isBlank()) {
+ // If the parameter has a concrete (non-empty) value
referencing a service instance id,
+ // generate a stable Versioned ID for it.
+ final String serviceId = getId(Optional.empty(),
parameterValue);
+ versionedParameter = mapParameter(parameter, serviceId);
+ } else {
+ // No referenced service and no parameter value specified;
map as null to avoid NPE
+ versionedParameter = mapParameter(parameter, null);
+ }
}
} else {
versionedParameter = mapParameter(parameter);
diff --git
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/registry/flow/mapping/NiFiRegistryFlowMapperTest.java
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/registry/flow/mapping/NiFiRegistryFlowMapperTest.java
index ec03e47003..489db2e7c5 100644
---
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/registry/flow/mapping/NiFiRegistryFlowMapperTest.java
+++
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/registry/flow/mapping/NiFiRegistryFlowMapperTest.java
@@ -30,6 +30,7 @@ import org.apache.nifi.connectable.Position;
import org.apache.nifi.connectable.Positionable;
import org.apache.nifi.connectable.Size;
import org.apache.nifi.controller.BackoffMechanism;
+import org.apache.nifi.controller.ComponentNode;
import org.apache.nifi.controller.ControllerService;
import org.apache.nifi.controller.ParameterProviderNode;
import org.apache.nifi.controller.ProcessorNode;
@@ -72,6 +73,8 @@ import org.apache.nifi.parameter.ParameterContext;
import org.apache.nifi.parameter.ParameterDescriptor;
import org.apache.nifi.parameter.ParameterProvider;
import org.apache.nifi.parameter.ParameterProviderConfiguration;
+import org.apache.nifi.parameter.ParameterReferenceManager;
+import org.apache.nifi.parameter.ParameterReferencedControllerServiceData;
import org.apache.nifi.parameter.StandardParameterProviderConfiguration;
import org.apache.nifi.processor.util.StandardValidators;
import org.apache.nifi.registry.VariableDescriptor;
@@ -154,6 +157,63 @@ public class NiFiRegistryFlowMapperTest {
when(parameterProvider.getIdentifier()).thenReturn(PARAMETER_PROVIDER_ID);
}
+ /**
+ * Fix for NIFI-14935: mapping parameter contexts should not NPE when a
Reference Parameter to a
+ * Controller Service has a null/empty value and the referenced versioned
service id is null. The
+ * parameter should be mapped with a null value.
+ */
+ @Test
+ public void testMapParameterReferenceToServiceWithNullValueMapsNull() {
+ final ProcessGroup processGroup = mock(ProcessGroup.class);
+
+ // Parameter Context with one parameter that references a Controller
Service but has a null value
+ final ParameterContext parameterContext = mock(ParameterContext.class,
Answers.RETURNS_DEEP_STUBS);
+ when(processGroup.getParameterContext()).thenReturn(parameterContext);
+ when(parameterContext.getName()).thenReturn("ctx");
+
when(parameterContext.getInheritedParameterContextNames()).thenReturn(Collections.emptyList());
+
+ final Map<ParameterDescriptor, Parameter> parametersMap = new
LinkedHashMap<>();
+ final ParameterDescriptor parameterDescriptor = new
ParameterDescriptor.Builder()
+ .name("ssl-service-ref")
+ .description("Reference to SSL Context Service")
+ .sensitive(false)
+ .build();
+ final Parameter parameter = mock(Parameter.class);
+ when(parameter.getDescriptor()).thenReturn(parameterDescriptor);
+ when(parameter.getValue()).thenReturn(null); // empty/null parameter
value
+ parametersMap.put(parameterDescriptor, parameter);
+ when(parameterContext.getParameters()).thenReturn(parametersMap);
+
+ // Parameter is referenced by a property that identifies a Controller
Service; versioned service id is null
+ final ParameterReferenceManager referenceManager =
parameterContext.getParameterReferenceManager();
+ final PropertyDescriptor referencingProperty = new
PropertyDescriptor.Builder()
+ .name("SSL Context Service")
+ .identifiesControllerService(ControllerService.class)
+ .build();
+ final ParameterReferencedControllerServiceData referencedData = new
ParameterReferencedControllerServiceData(
+ parameterDescriptor.getName(),
+ mock(ComponentNode.class),
+ referencingProperty,
+ ControllerService.class,
+ null // referenced versioned service id is null
+ );
+
when(referenceManager.getReferencedControllerServiceData(parameterContext,
parameterDescriptor.getName()))
+ .thenReturn(Collections.singletonList(referencedData));
+
+ // Mapping should succeed and the parameter value should be null
+ final Map<String, ParameterProviderReference>
parameterProviderReferences = new HashMap<>();
+ final Map<String, VersionedParameterContext> mapped =
+ flowMapper.mapParameterContexts(processGroup, true,
parameterProviderReferences);
+
+ final VersionedParameterContext ctx = mapped.get("ctx");
+ assertNotNull(ctx);
+ final VersionedParameter versionedParameter =
ctx.getParameters().stream()
+ .filter(p -> p.getName().equals("ssl-service-ref"))
+ .findFirst()
+ .orElseThrow(() -> new AssertionError("Expected parameter not
found"));
+ assertNull(versionedParameter.getValue());
+ }
+
/**
* Test mapping versioned process group's parameter contexts excluding
descendant versioned process groups
*/