0

MyProjectJmsListenerContainerFactory class:

@Configuration
public class MyProjectJmsListenerContainerFactory {

    @Bean
    public JmsListenerContainerFactory<?> myFactory(
            ConnectionFactory connectionFactory,
            DefaultJmsListenerContainerFactoryConfigurer configurer, 
            MyProjectJmsGlobalErrorHandler errorHandler) {
        ActiveMQConnectionFactory activeMQConnectionFactory =
                       (ActiveMQConnectionFactory)connectionFactory;
        RedeliveryPolicy redeliveryPolicy = new RedeliveryPolicy();
        redeliveryPolicy.setMaximumRedeliveries(1);
        activeMQConnectionFactory.setRedeliveryPolicy(redeliveryPolicy);

        DefaultJmsListenerContainerFactory factory = 
                 new DefaultJmsListenerContainerFactory();
        factory.setErrorHandler(errorHandler);
        configurer.configure(factory, activeMQConnectionFactory);
        return factory;
    }
}

MyProjectJmsGlobalErrorHandler class:

@Component
public class MyProjectJmsGlobalErrorHandler implements ErrorHandler {

    @Override
    public void handleError(Throwable throwable) {
        System.out.println("JMS EXCEPTION HANDLER CAUGHT THE EXCEPTION !!");       
    }
}

JMSTextMessageConverter class:

@Configuration
public class JMSTextMessageConverter {

    @Bean
    public MessageConverter jacksonJmsMessageConverter() {
        MappingJackson2MessageConverter mappingJackson2MessageConverter = 
                     new MappingJackson2MessageConverter();
        mappingJackson2MessageConverter.setTargetType(MessageType.TEXT);
        mappingJackson2MessageConverter.setTypeIdPropertyName("_type");

        return mappingJackson2MessageConverter;
    }   
}

JMSMessagePublisher class:

@Component
public class JMSMessagePublisher {

    private JmsTemplate jmsTemplate;

    private MessageConverter messageConverter;

    @Autowired
    public JMSMessagePublisher(JmsTemplate jmsTemplate,    
                           MessageConverter messageConverter) {
        this.jmsTemplate = jmsTemplate;
        this.messageConverter = messageConverter;
    }

    public void publishMessage() {
        jmsTemplate.setMessageConverter(messageConverter);
        jmsTemplate.convertAndSend("test.q1", "Hello World");
    }
}

JMSListener class:

@Component
public class JMSListener {

    @JmsListener(destination = "test.q1")
    public void subscribe(String message) throws Exception {
        System.out.println(" message received ::::::::"+message);
        throw new Exception("Exception from message listener ");
    }
}

I am throwing an exception from subscribe method above but could not get notified to to ErrorHandler and I could notice the below warning in the logs.

WARN 1993 --- [enerContainer-1] o.s.j.l.DefaultMessageListenerContainer  : 
Execution of JMS message listener failed, and no ErrorHandler has been set.

What is the issue with my JMS configuration i.e., how do I set up the ErrorHandler such that all exceptions are globally caught/notified inside handleError(Throwable throwable) method.

I publish the messages using publishMessage() method from JMSMessagePublisher class (given above).

Vasu
  • 21,832
  • 11
  • 51
  • 67

1 Answers1

2

The ErrorHandler is only to handle errors (exceptions) thrown by your listener while processing a message.

Since there is no connection, there is no message yet for which to handle an error.

You can write your own logic to try to get a connection from the connection factory from time-to-time.

EDIT

I just ran a test and it worked fine for me...

@SpringBootApplication
public class So49861714Application {

    public static void main(String[] args) {
        SpringApplication.run(So49861714Application.class, args);
    }

    @Bean
    public ApplicationRunner runner(JmsTemplate template) {
        return args -> template.convertAndSend("foo", "testMessage");
    }

    @Bean
    public DefaultJmsListenerContainerFactory jmsListenerContainerFactory(
            DefaultJmsListenerContainerFactoryConfigurer configurer,
            ConnectionFactory connectionFactory,
            ErrorHandler myErrorHandler) {
        DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
        configurer.configure(factory, connectionFactory);
        factory.setErrorHandler(myErrorHandler);
        return factory;
    }

    @Bean
    public ErrorHandler myErrorHandler() {
        return t -> {
            System.out.println("In error handler");
            t.printStackTrace();
        };
    }

    @JmsListener(destination = "foo")
    public void listen(String in) {
        System.out.println(in);
        throw new RuntimeException("test");
    }

}

and

testMessage
In error handler
org.springframework.jms.listener.adapter.ListenerExecutionFailedException: Listener method 'public void com.example.So49861714Application.listen(java.lang.String)' threw exception; nested exception is java.lang.RuntimeException: test
...
Caused by: java.lang.RuntimeException: test

I just noticed your factory bean is called myFactory but you don't specify it in the @JmsListener. If your application is a Spring Boot app, I am guessing the listener is using Boot's jmsListenerContainerFactory bean (which is the default bean name).

Vasu
  • 21,832
  • 11
  • 51
  • 67
Gary Russell
  • 166,535
  • 14
  • 146
  • 179
  • +1, Thanks for your answer, I got your point, updated the question above with the logs i.e., this time even if my listener throws an exception, it has not been notified to `ErrorHandler`, can you help? – Vasu Apr 17 '18 at 09:57