Spring Retry traversingCauses example (using RetryTemplateBuilder)

In my previous post under Spring Retry, I showed with example how to retry failed operations only for specific exceptions.

So for example if we configure Spring Retry (as shown in the below code) to retry only when NullPointerException is thrown

Code snippet 1


    RetryTemplateBuilder retryTemplateBuilder = RetryTemplate.builder();
    retryTemplateBuilder.retryOn(NullPointerException.class)

Spring Retry will retry the failed operation only when NullPointerException is thrown.

But what if NullPointerException causes another exception, say IllegalArgumentException, at that time Spring Retry will not retry the failed operation because NullPointerException is not the main exception thrown in this case. It is IllegalArgumentException that is the main exception thrown.

How to fix that.

We can fix this by taking help of “traversingCauses” method on RetryTemplateBuilder.

“traversingCauses” method configures the Spring Retry to go through the causes of the main exception and retry the failed operation if the cause of exception (which is another exception) matches with the exception Spring Retry is configured to retry.

To show with an example, we will be using the below Service class

Service class


public class Service3 {
    private int i = 0;

    public void executeExceptionWithCause() {
        i = i + 1;
        System.out.println("Executing 'executeExceptionWithCause' : " + i);
        NullPointerException nullPointerException = new NullPointerException();
        IllegalArgumentException illegalArgumentException = new IllegalArgumentException(nullPointerException);
        throw illegalArgumentException;
    }
}

In the above java code, IllegalArgumentException is thrown and the cause of it is another exception which is NullPointerException.

If we go through the code snippet 1 shown earlier for RetryTemplateBuilder, the above operation will not be retried as the main exception is IllegalArgumentException and not NullPointerException.

To fix this we take help of “traversingCauses” method as shown in the below code snippet


    RetryTemplate.builder().retryOn(NullPointerException.class).traversingCauses().build()

If we use the above code snippet, the Spring Retry will check the causes of the main exception and if any of the caused exception matches the exception declared, the failed operation will be retried.

Below is the complete main class for your reference

Main class


import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.retry.support.RetryTemplate;

public class Example26 {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("Example26.xml");
        Service3 service3 = (Service3) context.getBean("service3");

        RetryTemplate retryTemplate = RetryTemplate.builder().retryOn(NullPointerException.class).traversingCauses().build();

        try {
            retryTemplate.execute(retryContext -> { service3.executeExceptionWithCause(); return null;});
        } catch(IllegalArgumentException excep) {
            excep.printStackTrace();
        }
    }
}

Below is the output

Output


[INFO] ClassPathXmlApplicationContext - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@6576fe71: startup date [Tue May 03 11:23:22 IST 2022]; root of context hierarchy
[INFO] XmlBeanDefinitionReader - Loading XML bean definitions from class path resource [Example26.xml]
Executing 'executeExceptionWithCause' : 1
Executing 'executeExceptionWithCause' : 2
Executing 'executeExceptionWithCause' : 3
java.lang.IllegalArgumentException: java.lang.NullPointerException
    at Service3.executeExceptionWithCause(Service3.java:8)
    at Example26.lambda$0(Example26.java:13)
    at org.springframework.retry.support.RetryTemplate.doExecute(RetryTemplate.java:329)
    at org.springframework.retry.support.RetryTemplate.execute(RetryTemplate.java:209)
    at Example26.main(Example26.java:13)
Caused by: java.lang.NullPointerException
    at Service3.executeExceptionWithCause(Service3.java:7)
    ... 4 more

Leave a Reply