Retryable on WebFlux - spring

I've have a method which is annotated with #Scheduled and #Retryable. This method work fine with Mvc but the same method is not working on Webflux.
The scheduler works fine but Retryable is not happening. This happens only on Webflux.
#Scheduled(cron = "${config.refresh.interval}")
#Retryable(backoff = #Backoff(delayExpression = "${config.backoff.delay:999}"))
public void refreshConfig() {
// Load config values here
}
Boot Version - 2.6.7
spring-retry - 1.3.3

Related

Spring boot controller not accessed via postman || spring boot : 1.5.14.RELEASE

I am trying to create a simple spring boot application which has jersey jars as well for some internal rest client implementation to call. My application is starting fine but when trying to hit the controller method, nothing is called & on postman its saying as 404 Not Found.
Spring boot version: 1.5.14.RELEASE
Jersey Client: 2.25.1 (org.glassfish.jersey.core)
Controller class
#EnableAutoConfiguration(exclude = {SecurityAutoConfiguration.class, DataSourceAutoConfiguration.class})
#RequestMapping("/report")
public class ReportProcessController {
Controller method which I am trying to access
#RequestMapping(value = "/email", method = RequestMethod.GET)
#ResponseBody
public String sendEmail(HttpServletResponse response) {

Application failed to start after spring boot version upgrade from 2.1.18.RELEASE to 2.2.0.RELEASE

When we upgrade the spring-boot-starter-parent version from 2.1.8.RELEASE to 2.2.0.RELEASE, the application is not loading few beans. Due to this, application is failing. #PostConstuct is not able to add BCFIPS Provider in security provider.
#Configuration
#Slf4j
#ComponentScan(basePackages = "com.xxx.yyy.ekms.sdk")
#ConditionalOnProperty(name = "ekms.enabled", havingValue = "true")
public class EKMSClientSdkConfiguration extends ClientConfiguration
{
#PostConstruct
public void addSecurityProvider()
{
Security.addProvider(new BouncyCastleFipsProvider());
}
#Bean
public ApiClientBuilder apiClientBuilder()
{
return new DefaultApiClientBuilder();
}
}
Also, apiClientBuilder bean is not getting created.
The EKMSClientSdkConfiguration is extending ClientConfiguration, which is coming as part of another application jar. This class is not having any annotation.
public abstract class ClientConfiguration {
public ClientConfiguration()
{
}
public abstract void addSecurityProvider();
#Bean
public EKMSClient restClient() {
return new EKMSRestClientImpl(this.apiClient());
}
#Bean
public ApiClient apiClient() {
return Configuration.getDefaultApiClient();
}
}
In our case, EKMSClientSdkConfiguration bean is not getting created and the #PostConstruct is also not getting executed.
I went through the Spring Boot 2.2.RELEASE notes which is pointing to Spring Framework 5.2 upgrade guide. Here, I learned that spring boot 2.2.0 RELEASE is using Spring framework 5.2. In Spring framework 5.2, we have many changes.
It looks like this is the root cause of bean not getting loaded, but I am not sure about it.
Any help will be appreciated. Let me know if additional information is needed.
I found spring.main.lazy-initialization=true property in my application which was causing the above issue. When I removed it from the application.properties, This issue is resolved. This is the major change which was introduced in 2.2.0.RELEASE of spring boot

Error when using Spring Security 5 and Auth0

I am configuring my Spring Boot application using auth0. For that I am using the following tutorial: https://auth0.com/docs/quickstart/backend/java-spring-security5
But I am getting the following error:"
class com.nimbusds.jose.Algorithm cannot be cast to class com.nimbusds.jose.JWSAlgorithm (com.nimbusds.jose.Algorithm and com.nimbusds.jose.JWSAlgorithm are in unnamed module of loader 'app')
I am using Spring Boot 2.5.0-M2, and Kotlin (just in case it matters)
It is a bug in 5.5.0 pre releases of spring security which is used by spring boot 2.5.0.
There is a PR to fix this that hopefully will be released soon.
Until then you can create the JwTDecoder as a workaround:
#Bean
JwtDecoder jwtDecoder() {
String issuerUri = ...;
String jwkSetUri = ...;
OAuth2TokenValidator<Jwt> validator = JwtValidators.createDefaultWithIssuer(issuerUri);
NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withJwtSetUri(jwkSetUri).build();
jwtDecoder.setJwtValidator(validator);
return jwtDecoder;
}

Unit test - Problems testing #Retryable and #Recover

I have a component that's using #Retryable annotation and another service using that component. So I'm trying to test that the component using #Retryable annotation is actually retrying.
I've tried every solution there is on the web right now but nothing worked for me. I'm trying to create a unit test for this and not integration test. So far I've managed to get to the exception that's supposed to be thrown and #Retryable wasn't even retrying, the method just threw the exception and thats it.
This is the component using Retryable annotation:
#Component
public class OurComponent {
#Retryable(maxAttempts = 10,
backoff = #Backoff(delay = 2000),
value = {someException.class}
)
public void someMethod(SomeObject someObject) throws someException {
Object createObject = anotherMethod(someObject); //this method throws someException
...
}
}
And the service using this ourComponent:
#Service
public class someService {
private final OurComponent ourComponent;
public SomeService(OurComponent ourComponent) {
this.ourComponent = ourComponent;
}
...
public void methodUsingComponent() {
SomeObject someObject = new SomeObject(args);
ourComponent.someMethod(someObject);
}
}
Now I've tried to #InjectMocks and #MockBean this service and component but it still didn't work. Is it even possible to test #Retryable annotation without doing integration test?
If you use a unit test that doesn't use spring at all, you won't be able to test it easily.
This is due to the fact that annotations like this are recognized by spring and the corresponding bean is wrapped with a runtime-generated proxy that implements the "retry" logic.
Now, if you don't have spring who triggers all this mechanism, this #Retryable annotation is basically useless, mockito doesn't know anything about, so is Junit.
You could try to create a proxy like this manually (check what logic spring-retry invokes) but it looks to be an overkill. And frankly speaking, it doesn't give you anything. Unit test should check the functionality of your code and not the logic behind spring retry that was implemented by somewhere else and tested.

spring boot 2 + netty + servlet.context-path + not working

I am trying to create a spring-boot-2 REST api using spring-boot-starter-webflux and reactive Netty. I am trying to set the context-path as per the new properties to be defined in application.yml defined in Spring-Boot-2.
server.servlet.context-path: /api # Define the server context path
However it looks like Webflux, Netty doesn't use/recognise this property defined in application.yml.
If I use spring-boot-starter-web and Tomcat as the default server then it works fine and recognises context-path properly.
Didn't find anything mentioned about Netty's context-path in Spring Boot 2 documentation.
Spring Boot Version = 2.0.3.RELEASE
Please let me know if I missed something or this is the default behaviour of Webflux Netty ?
Configuring the context path is servlet-specific. when using WebFlux,
the configuration property was renamed to server.servlet.context-path and only for servlet based deployment.
You can read below thread to how you can deal with context path in webflux, please see comment
https://github.com/spring-projects/spring-boot/issues/10129#issuecomment-351953449
Webflux Context path issue thread
In spring boot 2.3.x you can set spring.webflux.base-path property
It worked for me with
spring.webflux.base-path=/myPath
but only when adding the hint in this comment: https://stackoverflow.com/a/67840678/8376373
which suggests to inject a WebFluxProperties Bean
#Bean
fun webFluxProperties(): WebFluxProperties {
return WebFluxProperties()
}
You can use a WebFilter to work around this limitation:
#Autowired
lateinit var serverProperties: ServerProperties
#Bean
fun contextPathWebFilter(): WebFilter {
val contextPath = serverProperties.servlet.contextPath
return WebFilter { exchange, chain ->
val request = exchange.request
if (request.uri.path.startsWith(contextPath)) {
chain.filter(
exchange.mutate()
.request(request.mutate().contextPath(contextPath).build())
.build())
} else {
chain.filter(exchange)
}
}
}

Resources