Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Spring Boot and RabbitMQ: JSON Serialization for Producers and Listeners

Tech 1

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

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.