I am currently working with the new RestClient in Spring Boot 3.2/Spring Framework 5.1, and I have encountered a challenge with handling 404 errors. My goal is to gracefully handle these errors without causing subsequent steps in my code to fail, particularly when converting the response body.
Example:
class CmsClient { pubic Policy getPolicy() { return restClient.get() .uri("some/url") .accept(MediaType.APPLICATION_JSON) .retrieve() .onStatus(ignore404()) .body(Policy.class); } public static ResponseErrorHandler ignore404() { return new ResponseErrorHandler() { @Override public boolean hasError(final ClientHttpResponse response) throws IOException { return response.getStatusCode() == HttpStatus.NOT_FOUND; } @Override public void handleError(final ClientHttpResponse response) { //Do nothing } }; }}
This is the exception I get:
org.springframework.web.client.RestClientException: Error while extracting response for type [package.Policy] and content type [application/json] at org.springframework.web.client.DefaultRestClient.readWithMessageConverters(DefaultRestClient.java:216) at org.springframework.web.client.DefaultRestClient$DefaultResponseSpec.readBody(DefaultRestClient.java:641) at org.springframework.web.client.DefaultRestClient$DefaultResponseSpec.body(DefaultRestClient.java:589) at package.CmsClient.getPolicy(CmsClient.java:27) at package.CmsClientTest.getPolicy_404_ThrowException_Test(CmsClientTest.java:61) at java.base/java.lang.reflect.Method.invoke(Method.java:580) at java.base/java.util.ArrayList.forEach(ArrayList.java:1596) at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)Caused by: org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: No content to map due to end-of-input at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:406) at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:354) at org.springframework.web.client.DefaultRestClient.readWithMessageConverters(DefaultRestClient.java:200) ... 7 moreCaused by: com.fasterxml.jackson.databind.exc.MismatchedInputException: No content to map due to end-of-input at [Source: (org.springframework.util.StreamUtils$NonClosingInputStream); line: 1, column: 0] at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59) at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1752) at com.fasterxml.jackson.databind.ObjectReader._initForReading(ObjectReader.java:360) at com.fasterxml.jackson.databind.ObjectReader._bindAndClose(ObjectReader.java:2095) at com.fasterxml.jackson.databind.ObjectReader.readValue(ObjectReader.java:1481) at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:395) ... 9 more
I anticipate that the method .body(Policy.class);
should return null instead of triggering an exception due to a MismatchedInputException. This behavior aligned with what was previously observed in WebClient, and I was expecting a similar approach in this context.
Current Solution: As a temporary measure, one can specify String.class in the body method call. However, this approach compromises the fluidity and ease of the code, necessitating additional handling with ObjectMapper and similar tools.