Spring amqp converter issue using rabbit listener
Asked Answered
B

2

24

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}]
Balefire answered 28/1, 2017 at 20:45 Comment(0)
A
33

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.

Anetta answered 28/1, 2017 at 21:14 Comment(3)
here you go - github.com/stackspring/sample . This will be best to identify issue. Pull that and give a try.Balefire
You need to add @Configuration to your RabbitConfig class - boot does not see the converter bean and therefore doesn't wire it in. BTW, you don't need admin and template beans; boot's autoconfig will add them for you. You also don't need a ConnectionFactory; you can put your credentials in application.yml (or .properties). See the boot reference documentation about RabbitMQ auto configuration. Your sample works for me when I added @Configuration. I'd also recommend upgrading to 1.4.4.Anetta
Extremely sorry for wasting your time :(. I should have paid more attention. I will do double checking before posting next time. Ya I dont need those beans just for what I did, but I am planning to experiment few more things on this.Balefire
H
0

Ran into the same issue, turns out that, git stash/merge messed up with my config, I need to include this package again in my main again:

@SpringBootApplication(scanBasePackages = {
        "com.example.amqp"  // <- git merge messed this up
})
public class TeamActivityApplication {

    public static void main(String[] args) {
        SpringApplication.run(TeamActivityApplication.class, args);
    }
}
Hufuf answered 18/1, 2023 at 21:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.