I am currently migrating an old declarative Feign client to Spring Web. The old client uses checked exceptions, and I would like to keep that behavior (it is very useful to be able to immediately know what kind of problems you might encounter when invoking the client, IDE suggesting which exceptions you need to catch etc.).
In Feign my client looked like this:
public interface SomeClientInterface {
@RequestLine("GET /some/path")
ReturnType someMethod() throws CheckedException1, CheckedException2;
}
Feign's ErrorDecoder
interface has the method Exception decode(String methodKey, Response response)
, which allows to decode server response into any checked exception.
The same client in Spring Web looks like this:
@HttpExchange
public interface SomeClientInterface {
@GetExchange("/some/path")
ReturnType someMethod() throws CheckedException1, CheckedException2;
}
Hovewer, Spring's ResponseErrorHandler
only allows to throw IOException
and unchecked exceptions (void handleError(ClientHttpResponse response) throws IOException
). The client is created using RestClient.Builder
with custom defaultStatusHandler
, and HttpServiceProxyFactory
.
I've been able to work around the issue by using lombok's @SneakyThrows
. But I think it would make much more sense to allow custom checked exceptions in ResponseErrorHandler
, possibly by changing handleError
to be able to throw Exception
, or by giving it return type Exception
(or Optional<Exception>
) and using the returned value as an exception thrown by invoking the client.
Comment From: rstoyanchev
It's not just ResponseErrorHandler
that would need to change. A checked exception would have to propagate all the way out of HttpServiceProxyFactory
, and that's quite a few levels:
org.springframework.web.client.HttpServerErrorException$InternalServerError: 500 Server Error on GET request for "http://view-localhost:44457/greeting": "Hello Spring!"
at org.springframework.web.client.HttpServerErrorException.create(HttpServerErrorException.java:102)
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:228)
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:163)
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:953)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:902)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:751)
at org.springframework.web.client.support.RestTemplateAdapter.exchangeForBody(RestTemplateAdapter.java:76)
at org.springframework.web.service.invoker.HttpServiceMethod$ExchangeResponseFunction.lambda$create$4(HttpServiceMethod.java:440)
at org.springframework.web.service.invoker.HttpServiceMethod$ExchangeResponseFunction.execute(HttpServiceMethod.java:397)
at org.springframework.web.service.invoker.HttpServiceMethod.invoke(HttpServiceMethod.java:134)
at org.springframework.web.service.invoker.HttpServiceProxyFactory$HttpServiceMethodInterceptor.invoke(HttpServiceProxyFactory.java:243)
It's the reason we don't propagate checked exceptions. They get declared on all levels while most levels only need to propagate but not handle them. They end up being generalized or wrapped as runtime exceptions anyway, and handled inconsistently, and effectively ignored.
Comment From: spring-projects-issues
If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.
Comment From: spring-projects-issues
Closing due to lack of requested feedback. If you would like us to look at this issue, please provide the requested information and we will re-open the issue.