-
Notifications
You must be signed in to change notification settings - Fork 38.9k
Description
The current RetryTemplate (7.0.3) has method:
@Override public <R extends @Nullable Object> R execute(Retryable<R> retryable) throws RetryExceptionWhat we want to indicate there is that the return value can be null, but e.g. IntelliJ does not understand it that way - see sample below (not executable, but compiles and shows the problem).
IntelliJ will claim that the @Nullable annotation on executeRequest() return type is unnecessary because it never returns null - but it clearly does, since doExecuteRequest() can return null and e.g. omitting @Nullable in doExecuteRequest() return type creates compiler warnings - as one would expect, based on definition of nullability for ResponseExtractor.
public class AA {
// just to have a variable reference for the example, not meant to execute
ClientHttpResponse response = null;
RetryTemplate retryTemplate = new RetryTemplate();
public <T> @Nullable T executeRequest(ResponseExtractor<T> responseExtractor) throws RetryException {
return retryTemplate.execute(() -> doExecuteRequest(responseExtractor));
}
private <T> @Nullable T doExecuteRequest(ResponseExtractor<T> responseExtractor) throws IOException {
return responseExtractor.extractData(response);
}
}Could it be that the RetryTemplate method signature should actually look more like this?
@Override public <R> @Nullable R execute(Retryable<@Nullable R> retryable) throws RetryExceptionOr something like that?
At least after a bit of consulting the internet, Copilot and whatever else, I tend to think that the current observation is not a bug in IntelliJ, but actually a problem with the annotations in RetryTemplate.
I am not a JSpecify expert, while I did quite a bit of refactoring to take it into use, this is still relatively new to me - so I might be missing something... please comment.
BTW, I am using IntelliJ 2025.3.1.
When I add the following:
@FunctionalInterface
interface SameButDifferent {
<R> @Nullable R execute(Retryable<@Nullable R> retryable) throws RetryException;
}
SameButDifferent sTemplate = null;
public <T> @Nullable T executeRequest2(ResponseExtractor<T> responseExtractor) throws RetryException {
return sTemplate.execute(() -> doExecuteRequest(responseExtractor));
}Then there is no nullability warning on executeRequest2().