Search code examples
rabbitmqamqpspring-amqpspring-rabbit

Spring amqp converter issue using rabbit listener


I think I am missing something here..I am trying to create simple rabbit listner which can accept custom object as message type. Now as per doc it says

In versions prior to 1.6, the type information to convert the JSON had to be provided in message headers, or a custom ClassMapper was required. Starting with version 1.6, if there are no type information headers, the type can be inferred from the target method arguments.

I am putting message manually in to queue using rabbit mq adm in dashboard,getting error like

Caused by: org.springframework.messaging.converter.MessageConversionException: Cannot convert from [[B] to [com.example.Customer] for GenericMessage [payload=byte[21], headers={amqp_receivedDeliveryMode=NON_PERSISTENT, amqp_receivedRoutingKey=customer, amqp_deliveryTag=1, amqp_consumerQueue=customer, amqp_redelivered=false, id=81e8a562-71aa-b430-df03-f60e6a37c5dc, amqp_consumerTag=amq.ctag-LQARUDrR6sUcn7FqAKKVDA, timestamp=1485635555742}]

My configuration:

@Bean
    public ConnectionFactory connectionFactory() {
        CachingConnectionFactory connectionFactory = new    CachingConnectionFactory("localhost");
        connectionFactory.setUsername("test");
        connectionFactory.setPassword("test1234");
        connectionFactory.setVirtualHost("/");
        return connectionFactory;
    }

    @Bean
    RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory) {
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
        return rabbitTemplate;
    }

    @Bean
    public AmqpAdmin amqpAdmin() {
        RabbitAdmin rabbitAdmin = new RabbitAdmin(connectionFactory());
        return rabbitAdmin;
    }

    @Bean
    public Jackson2JsonMessageConverter jackson2JsonMessageConverter() {
        return new Jackson2JsonMessageConverter();
    }

Also question is with this exception message is not put back in the queue.

I am using spring boot 1.4 which brings amqp 1.6.1.

Edit1 : I added jackson converter as above (prob not required with spring boot) and given contenty type on rmq admin but still got below, as you can see above I am not configuring any listener container yet.

Caused by: org.springframework.messaging.converter.MessageConversionException: Cannot convert from [[B] to [com.example.Customer] for GenericMessage [payload=byte[21], headers={amqp_receivedDeliveryMode=NON_PERSISTENT, amqp_receivedRoutingKey=customer, content_type=application/json, amqp_deliveryTag=3, amqp_consumerQueue=customer, amqp_redelivered=false, id=7f84d49d-037a-9ea3-e936-ed5552d9f535, amqp_consumerTag=amq.ctag-YSemzbIW6Q8JGYUS70WWtA, timestamp=1485643437271}]

Solution

  • If you are using boot, you can simply add a Jackson2JsonMessageConverter @Bean to the configuration and it will be automatically wired into the listener (as long as it's the only converter). You need to set the content_type property to application/json if you are using the administration console to send the message.

    Conversion errors are considered fatal by default because there is generally no reason to retry; otherwise they'd loop for ever.

    EDIT

    Here's a working boot app...

    @SpringBootApplication
    public class So41914665Application {
    
        public static void main(String[] args) {
            SpringApplication.run(So41914665Application.class, args);
        }
    
        @Bean
        public Queue queue() {
            return new Queue("foo", false, false, true);
        }
    
        @Bean
        public Jackson2JsonMessageConverter converter() {
            return new Jackson2JsonMessageConverter();
        }
    
        @RabbitListener(queues = "foo")
        public void listen(Foo foo) {
            System.out.println(foo);
        }
    
    
        public static class Foo {
    
            public String bar;
    
            public String getBar() {
                return this.bar;
            }
    
            public void setBar(String bar) {
                this.bar = bar;
            }
    
            @Override
            public String toString() {
                return "Foo [bar=" + this.bar + "]";
            }
    
        }
    
    }
    

    I sent this message

    Publish json message

    With this result:

    2017-01-28 21:49:45.509  INFO 11453 --- [           main] com.example.So41914665Application        : Started So41914665Application in 4.404 seconds (JVM running for 5.298)
    Foo [bar=baz]
    

    Boot will define an admin and template for you.