Skip to content

NullPointerException in StreamBridge when functionToInvoke returns null #3078

@StevenPG

Description

@StevenPG

Describe the issue

NullPointerException in StreamBridge when functionToInvoke returns null in StreamBridge. This happens reliably when an exception occurs when sending a message using StreamBridge with an object that fails to find a converter. I have a related issue in spring-cloud-function.

This happens for example when attempting to pass a NestedRuntimeException which has a self reference and throws a self-directed error. This results in no converter matching, and a null returned from functionToInvoke.

spring-cloud/spring-cloud-function#1237

I believe this is a valid issue because the RecordRecoverableProcessor added recently expects the following error handling BiConsumer BiConsumer<Record<KIn, VIn>, Exception>. Because the BiConsumer expects Exception, this means all exceptions handled that extend spring's NestedRuntimeException will throw this error if the caller decides to try to send the exception through StreamBridge.

It happens in postProcessResult on the following line

if (this.messageConverter != null && this.CLOUD_EVENT_CLASS != null && this.CLOUD_EVENT_CLASS.isAssignableFrom(result.getClass())) {
            convertedResult = this.messageConverter.toMessage(result, input.getHeaders());
        }

with the error

java.lang.NullPointerException: Cannot invoke "Object.getClass()" because "result" is null

because result is being inserted as null.

PR submitted for context (and potential resolution) #3079

To Reproduce

(Fastest way with a debugger)

  1. Locate the unit test test_2249() in StreamBridgeTests

  2. Place a breakpoint on the following line in the StreamBridge.send method using a debugger

resultMessage = (Message<?>) this.functionInvocationHelper.postProcessResult(resultMessage, null);
  1. In the spring-cloud-stream project, execute the unit test test_2249() in StreamBridgeTests

  2. Manually override resultMessage to null, continue the test and you will be met with the following error:

java.lang.NullPointerException: Cannot invoke "Object.getClass()" because "result" is null

(Unit test method)

This test can be added into StreamBridgeTests to verify

@Test
void test() {
	try (ConfigurableApplicationContext context = new SpringApplicationBuilder(
		TestChannelBinderConfiguration.getCompleteConfiguration(
			EmptyConfiguration.class)).web(WebApplicationType.NONE).run(
		"--spring.cloud.stream.source=outputA;outputB",
		"--spring.cloud.stream.bindings.outputA-out-0.producer.partition-count=3",
		"--spring.cloud.stream.bindings.outputB-out-0.destination=outputB",
		"--spring.jmx.enabled=false")) {
		StreamBridge streamBridge = context.getBean(StreamBridge.class);
		streamBridge.send("outputA-out-0",
                        // Random object example that will guarantee fail to find a converter
			new CodecException("someString")
			);
	}
}

Version of the framework
4.3.0-SNAPSHOT (verified in main)

Expected behavior

A null check before postProcessResult is executed with a thrown exception or logging.

I think this will routinely catch developers who use RecordRecoverableProcessor and attempt to send a NestedRuntimeException inheriting exception (or any other scenario where functionToInvoke can result in null)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions