Andrew Eells
Andrew Eells

Reputation: 815

Spring + AMQP serialise object message

I have an application that publishes a message using Spring AMQP’s RabbitTemplate and subscribes to the message on a POJO using MessageListenerAdapter, pretty much as per the Getting Started - Messaging with RabbitMQ guide.

void handleMessage(final String message) {...}

rabbitTemplate.convertAndSend(EXCHANGE_NAME, QUEUE_NAME, "message");

However, this is sending messages as String's; surely there is a way to send and receive Object messages directly?

I have tried registering a JsonMessageConverter but to no avail.

Any help would be greatly appreciated - at present I'm manually de/serialising Strings on either side which seems messy and I'm surprised this isn't a supported feature.

Upvotes: 1

Views: 3710

Answers (2)

Andrew Eells
Andrew Eells

Reputation: 815

Thanks @Artem for the hints. My code is pretty much as per the Getting Started Guide and I had already tried adding a Converter.

But as @Artem has pointed out, the trick is to register the converter with both the container, the listener adapter, and the rabbit template (which was auto-configured in the example).

So my @Configuration class now looks like so, in addition to whatever is mentioned in the Getting Started Guide:

@Bean
SimpleMessageListenerContainer container(final ConnectionFactory connectionFactory, final MessageListenerAdapter messageListenerAdapter,
    final MessageConverter messageConverter)
{
    final SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
    container.setConnectionFactory(connectionFactory);
    container.setQueueNames(QUEUE_NAME);
    container.setMessageListener(messageListenerAdapter);
    container.setMessageConverter(messageConverter);

    return container;
}

@Bean
RabbitTemplate rabbitTemplate(final ConnectionFactory connectionFactory, final MessageConverter messageConverter)
{
    final RabbitTemplate rabbitTemplate = new RabbitTemplate();
    rabbitTemplate.setConnectionFactory(connectionFactory);
    rabbitTemplate.setMessageConverter(messageConverter);

    return rabbitTemplate;
}

@Bean
MessageConverter messageConverter()
{
    return new Jackson2JsonMessageConverter();
}

@Bean
Receiver receiver()
{
    return new Receiver();
}

@Bean
MessageListenerAdapter listenerAdapter(final Receiver receiver, final MessageConverter messageConverter)
{
    return new MessageListenerAdapter(receiver, messageConverter);
}

which means the Receiver can have an Object method signature such as:

void handleMessage(final CbeEvent message)

Upvotes: 1

Artem Bilan
Artem Bilan

Reputation: 121272

I have tried registering a JsonMessageConverter but to no avail.

It would be better to see your attempt and figure out the issue on our side.

Right now I only can say that you should supply JsonMessageConverter for both sending and receiving parts.

I've just tested with the gs-messaging-rabbitmq:

@Autowired
RabbitTemplate rabbitTemplate;

@Autowired
MessageConverter messageConverter;

.....

@Bean
MessageListenerAdapter listenerAdapter(Receiver receiver, MessageConverter messageConverter) {
    MessageListenerAdapter adapter = new MessageListenerAdapter(receiver, "receiveMessage");
    adapter.setMessageConverter(messageConverter);
    return adapter;
}

@Bean
MessageConverter messageConverter() {
    return new Jackson2JsonMessageConverter();
}

 .....

System.out.println("Sending message...");
rabbitTemplate.setMessageConverter(messageConverter);
rabbitTemplate.convertAndSend(queueName, new Foo("Hello from RabbitMQ!"));

Where Receiver has been changed to this:

public void receiveMessage(Foo message) {
    System.out.println("Received <" + message + ">");
    latch.countDown();
}

So, the output is:

Waiting five seconds...
Sending message...
Received <Foo{foo='Hello from RabbitMQ!'}>

when we use Foo like this:

@Override
public String toString() {
    return "Foo{" +
            "foo='" + foo + '\'' +
            '}';
}

with appropriate getter and setter.

Upvotes: 1

Related Questions