0

I'm writing integration tests for my application that sends messages to RabbitMq. As part of my test config, I'm declaring some RabbitListeners to get these messages.

I know I'm not too far off, because this is working :

 @RabbitListener(bindings = @QueueBinding(
    value = @Queue(
        value = "myQueue",
        autoDelete = "true",
        exclusive = "false",
        durable = "false"),
    exchange = @Exchange(
        value = "myExchange",
        autoDelete = "true",
        durable = "true"),
    key = "myRoutingKey"))
public void confirmEligibilityMessage(Object eligibilityEvent) {
    log.info("received message [{}]", eligibilityEvent);
    receivedMessages.add(eligibilityEvent);
}

--> message is received

However, I would like the message to be converted directly to the expected type, so I'm modifying the signature of the method by adding the type of the payload :

public void confirmConsolidationEligibilityMessage(@Payload EligibilityEvent eligibilityEvent)

and I'm getting this issue :"No converter found to convert to.."

Caused by:       org.springframework.amqp.support.converter.MessageConversionException: Cannot   handle message
... 13 common frames omitted
Caused by: org.springframework.messaging.converter.MessageConversionException: No converter found to convert to class messaging.outgoing.EligibilityEvent, message=GenericMessage [payload={"requestCode":"someRequestCode","isEligible":false}, headers=...

I have tried what is proposed here and made my GlobalEventBusListener implement RabbitListenerConfigurer like this :

public class GlobalEventBusListener  implements RabbitListenerConfigurer {

private final List<Object> receivedMessages = new ArrayList<>();

@Override
public void configureRabbitListeners(RabbitListenerEndpointRegistrar registrar) {
    registrar.setMessageHandlerMethodFactory(myHandlerMethodFactory());
}

@Bean
public MessageConverter jackson2Converter() {
    MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
    return converter;
}

@Bean
public DefaultMessageHandlerMethodFactory myHandlerMethodFactory() {
    DefaultMessageHandlerMethodFactory factory = new DefaultMessageHandlerMethodFactory();
    factory.setMessageConverter(jackson2Converter());
    return factory;
}

But I still get issues because conversion doesn't happen properly - message is different though..

Caused by: java.lang.IllegalStateException: No suitable resolver for argument [0] [type=messaging.outgoing.EligibilityEvent]
HandlerMethod details: 
Controller [mocks.GlobalEventBusListener]
Method [public void mocks.GlobalEventBusListener.confirmEligibilityMessage(messaging.outgoing.EligibilityEvent)]

Any idea of what I could try ? I'm not sure how to investigate further.. Should I log all beans instantiated by Spring Boot and take it from here ? what kind of beans should be here so that it works ? With Spring Boot "magic", I initially thought that simply having a MessageConverter like below in my context would do the trick, but it looks like it's not the case :

@Bean
public MessageConverter jackson2Converter() {
    MappingJackson2MessageConverter converter = new MappingJackson2MessageConverter();
    return converter;
}  

Thanks !!

Community
  • 1
  • 1
Vincent F
  • 6,523
  • 7
  • 37
  • 79

4 Answers4

1

Use a Jackson2JsonMessageConverter from spring-amqp - see the documentation.

Also, starting with version 1.6, when using @RabbitListener annotations (on methods), the inferred type information is added to the MessageProperties;...

The framework configures the type the converter will convert to, based on the method signature.

Gary Russell
  • 166,535
  • 14
  • 146
  • 179
  • Thanks a lot Gary, I had overlooked this part of the doc. I was focusing on the receiver part, but I was not sending the message properly : I was sending it as a String, so content-type in headers was not set properly to Json. – Vincent F Oct 28 '16 at 03:52
1

If all messages have the same type (can be deserialized with the same MessageConverter) it is enough to add Jackson2JsonMessageConverter to your application context:

@Bean
MessageConverter messageConverter(ObjectMapper objectMapper) {
    Jackson2JsonMessageConverter jackson2JsonMessageConverter = new Jackson2JsonMessageConverter();
    jackson2JsonMessageConverter.setJsonObjectMapper(objectMapper);
    return jackson2JsonMessageConverter;
}

Passing ObjectMapper as a parameter lets you configure Jackson using Spring Boot configuration properties.

Since it wasn't very clear for me at the beginning how to configure Spring Boot and Spring Amqp to serialize/deserialize JSON messages I created sample project you may want to have a look: https://github.com/maciejwalkowiak/spring-boot-spring-amqp-java8-lombok-sample

Maciej Walkowiak
  • 12,372
  • 59
  • 63
1

Thanks to Gary's help and a little bit more reading on the documentation, I was able to fix it. By the way I'm using Spring amqp 1.5.6, ie < 1.6.

  • first thing is that I was sending the message as a Json String, bypassing the AmqpTemplate's converter : by passing my object directly to amqpTemplate.convertAndSend method, without converting it myself to Json, headers were set properly, to help the receiver identify the content is Json.
  • second, I simply had to add this in my config :

-

@Bean
public Jackson2JsonMessageConverter jackson2Converter() {
    Jackson2JsonMessageConverter converter = new Jackson2JsonMessageConverter();
    return converter;
}

@Bean
public RabbitListenerContainerFactory rabbitListenerContainerFactory() {
    SimpleRabbitListenerContainerFactory simpleRabbitListenerContainerFactory = new SimpleRabbitListenerContainerFactory();
    simpleRabbitListenerContainerFactory.setConnectionFactory(connectionFactory());
    simpleRabbitListenerContainerFactory.setMessageConverter(jackson2Converter());
    return simpleRabbitListenerContainerFactory;
}
Vincent F
  • 6,523
  • 7
  • 37
  • 79
0

I had a similar problem and what worked for me was to simply set the Jackson2Message message converter as

webSocketStompClient.messageConverter = new MappingJackson2MessageConverter()

I found useful info (and examples) about this on: https://github.com/Noozen/spring-boot-websocket-client#the-java-client

croc
  • 1,416
  • 1
  • 18
  • 24