0
votes

I am using RabbitMQ with Spring Boot to broker messages between two services. I am able to receive the message and format it but when I call a service class in the onMessage method, I get a null pointer exception error. Here is my message listener class which receives the message

public class QueueListener implements MessageListener{
    @Autowired
    private QueueProcessor queueProcessor;

    @Override
    public void onMessage(Message message) {
        String msg = new String(message.getBody());
        String output = msg.replaceAll("\\\\", "");
        String jsonified = output.substring(1, output.length()-1);

        JSONArray obj = new JSONArray(jsonified);

        queueProcessor.processMessage(obj);
    }
}

Calling the method processMessage throws null pointer exception enter image description here

Can someone point to me what I ma doing wrong?

2
What is line 30? The queueProcessor.processMessage(obj) call? Please update your question with the full stack and configuration of the QueueProcessorDarren Forsythe
Line 30 is queueProcessor.processMessage(obj); call. The QueueProcessor is a service class that extracts the queue JSON message from the queue and posts it to DB. I have tested that part from Postman (rest client) and its working fineBenjamin Mwendwa Munyoki
You definitely have to show the whole stack trace. It’s not clear from here what is the problemArtem Bilan
Best guess is you are using new QueueListener() instead of declaring it as a Spring-managed bean. Spring can only @Autowire things it knows about. If that's not it, show how you are configuring your listener container.Gary Russell

2 Answers

0
votes

I found out the issue was in the RabbitMqConfig class. Here is the code which was causing the error:

@Configuration
public class RabbitMqConfig {
private static final String QUEUE_NAME = "my.queue.name";

    @Bean
    public ConnectionFactory connectionFactory() {
    CachingConnectionFactory connectionFactory = new CachingConnectionFactory("<url.to.rabbit>");
    connectionFactory.setUsername("<username>");
    connectionFactory.setPassword("<password>");
    return connectionFactory;;
    }

    @Bean
    public Queue simpleQueue() {
        return new Queue(QUEUE_NAME);
    }

    @Bean
    public MessageConverter jsonMessageConverter(){
        return new Jackson2JsonMessageConverter();
    }

    @Bean
    public RabbitTemplate rabbitTemplate() {
        RabbitTemplate template = new RabbitTemplate(connectionFactory());
        template.setRoutingKey(QUEUE_NAME);
        template.setMessageConverter(jsonMessageConverter());
        return template;
    }

    @Bean
    public SimpleMessageListenerContainer userListenerContainer() {
        SimpleMessageListenerContainer listenerContainer = new SimpleMessageListenerContainer();
        listenerContainer.setConnectionFactory(connectionFactory());
        listenerContainer.setQueues(simpleQueue());
        listenerContainer.setMessageConverter(jsonMessageConverter());
        listenerContainer.setMessageListener(new QueueListener());
        listenerContainer.setAcknowledgeMode(AcknowledgeMode.AUTO);
        return listenerContainer;
    }
}

The line listenerContainer.setMessageListener(new QueueListener()); was the source of the error. I solved it by Autowiring the class instead of using new. Here is the working code

@Configuration
public class RabbitMqConfig {
private static final String QUEUE_NAME = "my.queue.name";

    @Autowired
    private QueueListener queueListener;

    @Bean
    public ConnectionFactory connectionFactory() {
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory("<url.to.rabbit>");
        connectionFactory.setUsername("<username>");
        connectionFactory.setPassword("<password>");
        return connectionFactory;
    }

    @Bean
    public Queue simpleQueue() {
        return new Queue(QUEUE_NAME);
    }

    @Bean
    public MessageConverter jsonMessageConverter(){
        return new Jackson2JsonMessageConverter();
    }

    @Bean
    public RabbitTemplate rabbitTemplate() {
        RabbitTemplate template = new RabbitTemplate(connectionFactory());
        template.setRoutingKey(QUEUE_NAME);
        template.setMessageConverter(jsonMessageConverter());
        return template;
    }

    /*@Bean
    public SimpleMessageListenerContainer userListenerContainer() {
        SimpleMessageListenerContainer listenerContainer = new SimpleMessageListenerContainer();
        listenerContainer.setConnectionFactory(connectionFactory());
        listenerContainer.setQueues(simpleQueue());
        listenerContainer.setMessageConverter(jsonMessageConverter());
        listenerContainer.setMessageListener(queueListener);
        listenerContainer.setAcknowledgeMode(AcknowledgeMode.AUTO);
        return listenerContainer;
    }
}

Hope this helps someone else

0
votes

Make sure the QueueListener is a component class or service class that can be managed by the Spring IoC. Otherwise, the config class cannot make this a bean out of the box, since this is just a normal Java class that need to be in the container @runtime.

So when u write new QueueListener() in yr config class, then the Java class is not in the SpringContext at the time when the config class is instantiated and is therefore null.

Hope this helps clear out some of this issue!