Spring Boot and RabbitMQ: JSON Serialization for Producers and Listeners
RabbitMQ transports raw bytes. Too exchange domain objects as JSON, you can serialize manually or configure Spring AMQP to handle JSON automatically for both producers and consumers.
Manual JSON serialization with ObjectMapper
You can convert a POJO to JSON yourself and publish the resulting bytes. This gives full control over headers like content type.
package com.example.messaging.producer;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.core.MessagePropertiesBuilder;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.nio.charset.StandardCharsets;
@Service
public class OrderPublisher {
private final RabbitTemplate amqp;
private final ObjectMapper json;
@Autowired
public OrderPublisher(RabbitTemplate amqp, ObjectMapper json) {
this.amqp = amqp;
this.json = json;
}
public void publish(Order payload) {
try {
byte[] body = json.writeValueAsBytes(payload);
MessageProperties props = MessagePropertiesBuilder.newInstance()
.setContentType(MessageProperties.CONTENT_TYPE_JSON)
.setContentEncoding(StandardCharsets.UTF_8.name())
.build();
Message amqpMessage = new Message(body, props);
// default exchange "" with routingKey == queue name
amqp.send("", BrokerNames.ORDERS_QUEUE, amqpMessage);
} catch (JsonProcessingException ex) {
throw new IllegalStateException("JSON encode failed", ex);
}
}
}
Producer-side JSON converter (recommended)
Instead of serializing in every publisher, configure a Jackson-based message converter for RabbitTemplate. Then send POJOs directly, and the template emits JSON and appropriate headers (e.g., content-type and type id).
package com.example.messaging.config;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AmqpProducerConfig {
@Bean
public MessageConverter producerJsonMessageConverter() {
return new Jackson2JsonMessageConverter();
}
@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory,
MessageConverter producerJsonMessageConverter) {
RabbitTemplate template = new RabbitTemplate(connectionFactory);
template.setMessageConverter(producerJsonMessageConverter);
return template;
}
}
Usage with the configured template:
rabbitTemplate.convertAndSend(BrokerNames.ORDERS_QUEUE, order);
In the RabbitMQ management UI, you will see a JSON payload and headers that include the Java type identifier used for deserialization.
Consumer-side JSON deserialization
To have @RabbitListener methods receive typed objects, register a JSON message converter for listener method arguments. One approach is to plug a MappingJackson2MessageConverter via RabbitListenerConfigurer.
package com.example.messaging.consumer;
import org.springframework.amqp.rabbit.annotation.RabbitListenerConfigurer;
import org.springframework.amqp.rabbit.listener.RabbitListenerEndpointRegistrar;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.messaging.converter.MappingJackson2MessageConverter;
import org.springframework.messaging.handler.annotation.support.DefaultMessageHandlerMethodFactory;
import org.springframework.messaging.handler.annotation.support.MessageHandlerMethodFactory;
@Configuration
public class AmqpConsumerConfig implements RabbitListenerConfigurer {
@Override
public void configureRabbitListeners(RabbitListenerEndpointRegistrar registrar) {
registrar.setMessageHandlerMethodFactory(listenerMethodFactory());
}
@Bean
public MessageHandlerMethodFactory listenerMethodFactory() {
DefaultMessageHandlerMethodFactory factory = new DefaultMessageHandlerMethodFactory();
factory.setMessageConverter(new MappingJackson2MessageConverter());
return factory;
}
}
Example listener that receives a POJO directly:
package com.example.messaging.consumer;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
@Component
public class OrderHandler {
@RabbitListener(queues = BrokerNames.ORDERS_QUEUE)
public void handle(Order incoming) {
// process order
}
}