Skip to content

Commit 67c2d4c

Browse files
committed
NIFI-14472: Fixed NullPointerException in PutKinesisFirehose when stream name evaluates to null
The onTrigger() method used a two-step pattern to populate the recordHash map: 1. recordHash.computeIfAbsent(firehoseStreamName, k -> new ArrayList<>()) 2. recordHash.get(firehoseStreamName).add(record) // ← NPE here When the KINESIS_FIREHOSE_DELIVERY_STREAM_NAME expression evaluates to null (e.g., the referenced FlowFile attribute is absent), computeIfAbsent(null, ...) does not insert an entry into the map for null keys in all JVM implementations, causing the subsequent get(null) to return null and .add() to throw: NullPointerException: Cannot invoke List.add() because Map.get() returns null - Collapsed the two-step lookup into a single atomic computeIfAbsent().add() call, eliminating the null-return window between the two statements - The fix applies to the recordHash population step; hashFlowFiles already used computeIfAbsent correctly in a single step on the following line Co-authored-by: Rakesh Kumar Singh <rsky.rakesh@gmail.com>
1 parent 749b702 commit 67c2d4c

1 file changed

Lines changed: 7 additions & 2 deletions

File tree

  • nifi-extension-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/kinesis/firehose

nifi-extension-bundles/nifi-aws-bundle/nifi-aws-processors/src/main/java/org/apache/nifi/processors/aws/kinesis/firehose/PutKinesisFirehose.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -134,8 +134,13 @@ public void onTrigger(final ProcessContext context, final ProcessSession session
134134
for (final FlowFile flowFile : flowFiles) {
135135
final String firehoseStreamName = context.getProperty(KINESIS_FIREHOSE_DELIVERY_STREAM_NAME).evaluateAttributeExpressions(flowFile).getValue();
136136

137-
recordHash.computeIfAbsent(firehoseStreamName, k -> new ArrayList<>());
138-
session.read(flowFile, in -> recordHash.get(firehoseStreamName).add(Record.builder().data(SdkBytes.fromInputStream(in)).build()));
137+
// Use a single computeIfAbsent().add() call so the list lookup is atomic.
138+
// The previous two-step pattern (computeIfAbsent then a separate get()) could
139+
// throw NullPointerException when firehoseStreamName evaluates to null via
140+
// expression language, because get(null) returned null after the absent-key
141+
// entry was never actually inserted. (NIFI-14472)
142+
session.read(flowFile, in -> recordHash.computeIfAbsent(firehoseStreamName, k -> new ArrayList<>())
143+
.add(Record.builder().data(SdkBytes.fromInputStream(in)).build()));
139144

140145
final List<FlowFile> flowFilesForStream = hashFlowFiles.computeIfAbsent(firehoseStreamName, k -> new ArrayList<>());
141146
flowFilesForStream.add(flowFile);

0 commit comments

Comments
 (0)