Sping retry throws RetryExhaustedException when exception is not included in #Retryable - spring-retry

I am using spring-retry 1.2.5. In my code I am using #Retryable and #CircuitBreaker annotation but whenever there is an exception which is not mentioned in include attribute I am getting RetryExhaustedException instead of the thrown checked exception.
I found that we need to set the throwLastExceptionOnExhausted to true in RetryTemplate.
I added a RetryTemplate bean in the config class and set the property to true but at runtime
the created bean is not getting used.
Basically #Retryable annotation is not using the bean which I created in configuration.
How can I set throwLastExceptionOnExhausted property when using #Retryable annotation ?

There are a couple of options.
Wire up your own interceptor bean and use it in the #Retryable interceptor property.
Add a #Recover method and re-throw the exception from there.
2 is probably the easiest.

Related

#EnableAutoConfiguration(exclude =...) on tests failed in Spring Boot 2.6.0

I tried to upgrade my data-mongo example project to Spring Boot 2.6.0. There is a test designed to run against Testcontainers, I also included the embedded mongo dep for other tests, so I have to exclude the AutoConfiguration for embedded mongo to make sure this test working on Docker/testcontainers.
The following configuration worked well with Spring Boot 2.5.6.
#DataMongoTest
#ContextConfiguration(initializers = {MongodbContainerInitializer.class})
#EnableAutoConfiguration(exclude = EmbeddedMongoAutoConfiguration.class)
#Slf4j
#ActiveProfiles("test")
public class PostRepositoryTest {}
But after upgrading to Spring Boot 2.6.0 and running the application, I got the exception like this.
[ main] s.c.a.AnnotationConfigApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: o
rg.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'embeddedMongoServer' defined in class path resource [org/springframework/boot/autoconfig
ure/mongo/embedded/EmbeddedMongoAutoConfiguration.class]: Unsatisfied dependency expressed through method 'embeddedMongoServer' parameter 0; nested exception is org.springframework.bea
ns.factory.BeanCreationException: Error creating bean with name 'embeddedMongoConfiguration' defined in class path resource [org/springframework/boot/autoconfigure/mongo/embedded/Embed
dedMongoAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [de.flap
doodle.embed.mongo.config.MongodConfig]: Factory method 'embeddedMongoConfiguration' threw exception; nested exception is java.lang.IllegalStateException: Set the spring.mongodb.embedd
ed.version property or define your own MongodConfig bean to use embedded MongoDB
Obviously, #EnableAutoConfiguration(exclude =...) did not affect the context in tests when upgrading to Spring Boot 2.6.0.
Update: Temporarily resolved it, see my answer below.
Just add:
#TestPropertySource(properties = "spring.mongodb.embedded.version=3.5.5")
annotation before your Unit Test and it will start working.
#Henning's answer has a good explanation of why you need this.
As of Spring Boot 2.6, the property spring.mongodb.embedded.version must be set to use the auto-configured embedded MongoDB. It's mentioned in the release notes: https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.6-Release-Notes#embedded-mongo
This is also what the error message you posted, advises to do: Set the spring.mongodb.embedd ed.version property or define your own MongodConfig bean to use embedded MongoDB
The annotation #DataMongoTest is meta-annotated with #ImportAutoConfiguration and #AutoConfigureDataMongo, and is designed to trigger auto-configuration of MongoDB unless explicitly disabled as you do in the working configuration examples.
In your first configuration example, the annotation #EnableAutoConfiguration(exclude = EmbeddedMongoAutoConfiguration.class) does not override this effect of #DataMongoTest.
With Spring Boot 2.5.6, the auto-configured MongodConfig bean is most likely also part of the application context but not effectively used. But this depends on the rest of the code and in particular on the MongodbContainerInitializer.
Use #ImportAutoConfiguration(exclude = ...) or #DataMongoTest(excludeAutoConfiguration = ...) on test classes to overcome this barrier when upgrading to Spring Boot 2.6.0.
#DataMongoTest
#ImportAutoConfiguration(exclude = EmbeddedMongoAutoConfiguration.class)
//other config are ommitted
public class PostRepositoryTest {}
//or
#DataMongoTest(excludeAutoConfiguration = EmbeddedMongoAutoConfiguration.class)
public class PostRepositoryTest {}

Spring Integration causes multiple beans error

I'm using Spring Boot and trying use Spring integration (because I want to use its SFTP client). But I got the following error:
Description:
Parameter 0 of constructor in com.example.demo.service.ServiceOne required a single bean, but 2 were found:
- applicationTaskExecutor: defined by method 'applicationTaskExecutor' in class path resource [org/springframework/boot/autoconfigure/task/TaskExecutionAutoConfiguration.class]
- taskScheduler: defined in null
Action:
Consider marking one of the beans as #Primary, updating the consumer to accept multiple beans, or using #Qualifier to identify the bean that should be consumed
I'm sure that the error happens after adding dependencies for spring-integration. I've tried to use #Qualifier("applicationTaskExecutor") and creating a bean with #Primary annotation but still unable to run the application. How to fix it?
As error stated there are two TaskExecutor beans in the application context.
One is auto-configured by the TaskExecutionAutoConfiguration and another by Spring Integration for its pollers features which is essentially a TaskScheduler.
What the error description suggest is to use a #Qualifier("applicationTaskExecutor") on the ServiceOne 's Parameter 0 of constructor. You don't need to have #Primary bean because the story is about beans created outside of your code.

Correct way to find if spring context was started

In my spring bean I want to use send spring event functionality. The problem is event can't be sent if spring context was not initialized and my bean by some reasons can send events before that happen.
I used the following:
implement ApplicationContextAware and use ConfigurableApplicationContext.isActive() - this becomes true in the beginning of the context initialization phase
use ConfigurableApplicationContext.isRunning() - this throws exception IllegalStateException("LifecycleProcessor not initialized...
listen for ContextRefreshedEvent - this doesn't work because this is inner bean and is used as a property for the bean that implements BeanFactoryPostProcessor
implementing SmartLifecycle also doesn't work because for inner beans
So what is the EASY and correct way to determine if context is running and event can be sent?
Hopefully this is already fixed SPR-13667 in spring 4.1.7.

Spring Boot + Spring Integration Java DSL + AOP : Fails to proxy the Gateway interface

Hi I have a spring boot application, which starts a spring integration flow, through a gateway interface, using Java DSL. Everything works fine on its own. I added AOP to capture exceptions, with #EnableAspectJAutoProxy(proxyTargetClass = true)
At this stage, it gives the error:
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'jobInitiator': Post-processing of
FactoryBean's singleton object failed; nested exception is
org.springframework.aop.framework.AopConfigException: Could not
generate CGLIB subclass of class [class com.sun.proxy.$Proxy54]:
Common causes of this problem include using a final class or a
non-visible class; nested exception is
java.lang.IllegalArgumentException: Cannot subclass final class class
com.sun.proxy.$Proxy54
When I remove the proxyTargetClass = true, it works but the advices are not triggered.
Any help? Is there a way to start the spring integration flow without a gateway?
There is no class associated with the gateway Proxy so you can't advise it.
Is there a way to start the spring integration flow without a gateway?
Instead of using the gateway, declare a bean of type MessagingTemplate and use template.sendAndReceive(someMessage) or template.convertSendAndReceive(somePojo) instead. See here.
(The gateway uses a MessagingTemplate internally; the gateway unwraps a MessagingException and throws the cause, the template does not).
It also does not support an error channel.
To get closer to the gateway functionality, you can subclass MessagingGatewaySupport and invoke its sendAndReceive() method(s).

Problem using SpringBeanAutowiringInterceptor with #Value annotation in a Stateless Session Bean

I'm using spring 3.0.5 in JBoss and when I try to use "#Value" annotation like this #Value("${terminal.type}") in an statless Session Bean annotated with #Interceptors(SpringBeanAutowiringInterceptor.clas s), I receive a IllegalArgumentException "'name' must not be null".
No problem with #Autowired annotation.
In SpringBeanAutowiringInterceptor class the metadata.inject() method is called with the bean name argument set to null.
Do I need to specify the bean name somewhere ?
(Same problem was asked here by another user: http://forum.springsource.org/showthread.php?94930-Problem-using-SpringBeanAutowiringInterceptor-with-Value-annotation, but was unanswered)
This will be fixed for 3.0.6 and 3.1:
https://jira.springsource.org/browse/SPR-8621

Resources