blackr1234
blackr1234

Reputation: 1486

How to use StreamBridge to send String message and bypass message conversion?

Background

Consider this sample code:

streamBridge.send("supply-out-0", (Object) "[hello world]", MediaType.TEXT_PLAIN);

With the above code, I am sending a very simple plain text String object data to a stream binding.

Notice the square brackets (i.e. [, ]) that are added intentionally into the message content.


Problem

Because of the square brackets, this fails with below error:

java.lang.IllegalStateException: Failed to convert. Possible bug as the conversion probably shouldn't have been attampted here
    at org.springframework.cloud.function.json.JacksonMapper.doFromJson(JacksonMapper.java:70)
    at org.springframework.cloud.function.json.JsonMapper.fromJson(JsonMapper.java:94)

It also gives the same error even with below binding-level content-type config:

spring:
  cloud:
    stream:
      bindings:
        supply-out-0:
          destination: xxx
          binder: xxx
          content-type: text/plain
# ... omitted ...

Question and my thought

I feel like this is a bug, will probably report it later in their GitHub.

Right now I need a way to fix it (the implementation code, not my message content). Does anyone know how?

What I know so far is, this binding, supply-out-0, gets its name by concatenating the function name of the supplier and -out- and the index (always 0 for single output).

That function gets called every second, but no way I can call it manually (e.g. from an HTTP request endpoint call) and provide an input message as it accepts no argument.

@Bean
public Supplier<String> supply() {
    return () -> "Hello World";
}

So, I feel like StreamBridge is the only way to manually trigger Spring Cloud Stream to send a message to my messaging topic. But unfortunately, it does not work as expected.


Dependency versions

Dependency Version
spring-cloud-dependencies 2021.0.3
spring-boot-dependencies 2.7.1
spring-cloud-stream Tried both 3.2.4 (managed) and 3.2.6 (override)

Others

Note: The type casting above is required to resolve compilation error coming from ambiguous method call 😅.

Upvotes: 0

Views: 3024

Answers (1)

Gary Russell
Gary Russell

Reputation: 174719

It looks like a bug in spring-cloud-function to me.

It is incorrectly assuming that the payload is a json collection because it "looks" like one...

Caused by: java.lang.IllegalStateException: Failed to convert. Possible bug as the conversion probably shouldn't have been attampted here
    at org.springframework.cloud.function.json.JacksonMapper.doFromJson(JacksonMapper.java:70) ~[spring-cloud-function-context-3.2.8.jar:3.2.8]
    at org.springframework.cloud.function.json.JsonMapper.fromJson(JsonMapper.java:94) ~[spring-cloud-function-context-3.2.8.jar:3.2.8]
    at org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry$FunctionInvocationWrapper.fluxifyInputIfNecessary(SimpleFunctionRegistry.java:829) ~[spring-cloud-function-context-3.2.8.jar:3.2.8]
if (JsonMapper.isJsonStringRepresentsCollection(payload)
        && !FunctionTypeUtils.isTypeCollection(this.inputType) && !FunctionTypeUtils.isTypeArray(this.inputType)) {
    MessageHeaders headers = ((Message) input).getHeaders();
    Collection collectionPayload = jsonMapper.fromJson(payload, Collection.class);
JsonMapper.isJsonStringRepresentsCollection(payload)

returns true. I suggest you raise an issue against that project.

Upvotes: 1

Related Questions