Search code examples
javaspringspring-bootspring-amqpspring-rabbit

Not able to configure resolver for my incoming RabbitMq message


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 !!


Solution

  • 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;
    }