3

I followed my previous question Spring Cloud Stream message from/to JSON conversion configuration and configured stream as described, yet, I can't make it work correctly.

My setup is as follows. I have two apps A and B. App A uses input channel one, output two. App B uses input two. Channel two is configured with content type application/json.

App A. Properties.

spring.cloud.stream.bindings.input.destination=one
spring.cloud.stream.bindings.input.group=default

spring.cloud.stream.bindings.output.destination=two
spring.cloud.stream.bindings.output.content-type=application/json

Listener method.

@ServiceActivator(inputChannel = Processor.INPUT, outputChannel = Processor.OUTPUT)
public Dto handle(byte[] payload) throws IOException {
    final Dto dto = new ObjectMapper().readValue(payload, Dto.class);
    logger.info("{}", dto);
    dto.setId(dto.getId() + 1000);
    return dto;
}

App B. Properties.

spring.cloud.stream.bindings.input.destination=two
spring.cloud.stream.bindings.input.group=default
spring.cloud.stream.bindings.input.content-type=application/json

Listener method.

@ServiceActivator(inputChannel = Sink.INPUT)
public void handle(Dto dto) throws IOException {
    logger.info("DTO {}", dto);
}

When I manually send a message with proper JSON string to channel one, it is processed correctly and send to channel two as a JSON message (headers exactly the same as described in above mentioned question). After that, it's received on channel two by App B and exception is thrown: Method handle(java.lang.String) cannot be found

Of course when I create both methods, handling Dto and String as an input, it works, but always String method is invoked and have to deserialize the payload by myself.

Am I mistaken somewhere? How do I setup method with such signature: public Dto handle(Dto incoming)?

Community
  • 1
  • 1
wst
  • 4,040
  • 4
  • 41
  • 59
  • Why didn't you use `StreamListener` instead of `ServiceActivator` for your App B? I am not 100% sure but I think your problem could have be fixed using `StreamListener` instead of changing the `content-type` property. – Gooseman Jan 29 '17 at 20:49
  • At the time, such option wasn't available. But, yeah, that is a good advice. – wst Jan 30 '17 at 01:40

2 Answers2

2

You should change the content-type declaration of input of AppB to

application/x-java-object;type=your.package.Dto.

As it is specified in your question, of course you accept JSON strings only.

Alexander
  • 50
  • 5
  • I don't need Java serialization. Take a look at the subject - I need JSON messages. – wst Mar 23 '16 at 14:42
  • True, you would leave the content-type declaration of output of AppA to have JSON output, but AppB should be told via this content-type declaration that an according MessageConverter should convert the payload into a Dto object. The messages on the channel will be JSON, as one can see during debugging. – Alexander Mar 23 '16 at 15:01
  • This actually works, thank you. Incredibly non-intuitive, considering how other Spring components work (AMQP or Rest). – wst Mar 24 '16 at 00:50
0

if use @StreamListener you don't have to use the answer way, but you have to remove (don't specify anything, otherwise it will be a json string):

spring.cloud.stream.bindings.input.content-type=application/json

from AppB properties

source (old docs but still valid): https://docs.spring.io/spring-cloud-stream/docs/Brooklyn.RELEASE/reference/html/contenttypemanagement.html#__literal_streamlistener_literal_and_message_conversion

Bashar Ali Labadi
  • 1,014
  • 1
  • 11
  • 19