Search code examples
javarabbitmqspring-amqpspring-rabbit

rabbitmq consume json message and convert into Java object


I have put together a java test. It puts a message on a queue and returns it as a string. What Im trying to achieve is for it to it convert into the java object SignUpDto. I have stripped down the code as much as possible for the question.

The question:

How do I modify the test below to convert into a object?


SignUpClass

public class SignUpDto {
    private String customerName;
    private String isoCountryCode;
    ... etc
}

Application - Config class

@Configuration
public class Application  {

    @Bean
    public ConnectionFactory connectionFactory() {
        return new CachingConnectionFactory("localhost");
    }

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

    @Bean
    public RabbitTemplate rabbitTemplate() {

        // updated with @GaryRussels feedback
        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory());
        rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
        return rabbitTemplate;
    }

    @Bean
    public Queue myQueue() {
        return new Queue("myqueue");
    }
}

The Test

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {Application.class})
public class TestQueue {

    @Test
    public void convertMessageIntoObject(){

        ApplicationContext context = new AnnotationConfigApplicationContext(Application.class);
        AmqpTemplate template = context.getBean(AmqpTemplate.class);

        String jsonString = "{ \"customerName\": \"TestName\", \"isoCountryCode\": \"UK\" }";

        template.convertAndSend("myqueue", jsonString);

        String foo = (String) template.receiveAndConvert("myqueue");

        // this works ok    
        System.out.println(foo);

        // How do I make this convert
        //SignUpDto objFoo = (SignUpDto) template.receiveAndConvert("myqueue");
        // objFoo.toString()  

    }
}

Solution

  • Configure the RabbitTemplate with a Jackson2JsonMessageConverter.

    Then use

    template.convertAndSend("myqueue", myDto);
    
    ...
    
    SignUpDto out = (SignUpDto) template.receiveAndConvert("myQueue");
    

    Note that the outbound conversion sets up the content type (application/json) and headers with type information that tells the receiving converter what object type to create.

    If you really do want to send a simple String of JSON, you need to set the content type to application/json. To help the inbound conversion, you can either set the type headers (look at the converter source for information), or you can configure the converter with a ClassMapper to determine the type.

    EDIT

    <rabbit:template id="amqpTemplate" connection-factory="connectionFactory"
             message-converter="json" />
    
    <bean id="json"
     class="org.springframework.amqp.support.converter.Jackson2JsonMessageConverter" />
    

    Or, since you are using Java Config; simply inject one into your template definition.

    EDIT2

    If you want to send a plain JSON string; you need to help the inbound converter via headers.

    To set the headers...

    template.convertAndSend("", "myQueue", jsonString, new MessagePostProcessor() {
    
        @Override
        public Message postProcessMessage(Message message) throws AmqpException {
            message.getMessageProperties().setContentType("application/json");
            message.getMessageProperties().getHeaders()
                .put(AbstractJavaTypeMapper.DEFAULT_CLASSID_FIELD_NAME, "foo.SignUpDto");
            return message;
        }
    });
    

    Bear in mind, though, that this sending template must NOT have a JSON message converter (let it default to the SimpleMessageConverter). Otherwise, the JSON will be double-encoded.