Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Not able to return ResponseEntity with Exception Details in spring

I have created a Spring Restful Service and Spring MVC application.

Restful Service :: Restful service returns an entity if its existing in DB. If it doesn't exist It returns a custom Exception information in ResponseEntity object.

It is working as expected tested using Postman.

@GetMapping(value = "/validate/{itemId}", produces = { MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_XML_VALUE })
public ResponseEntity<MyItem> validateItem(@PathVariable Long itemId, @RequestHeader HttpHeaders httpHeaders) {

    MyItem myItem = myitemService.validateMyItem(itemId);
    ResponseEntity<MyItem> responseEntity = null;
    if (myItem == null) {
        throw new ItemNotFoundException("Item Not Found!!!!");
    }
    responseEntity = new ResponseEntity<MyItem>(myItem, headers, HttpStatus.OK);
    return responseEntity;
}

If the requested Entity does not exist Restful Service returns below.

@ExceptionHandler(ItemNotFoundException.class)
public ResponseEntity<ExceptionResponse> itemNotFEx(WebRequest webRequest, Exception exception) {
    System.out.println("In CREEH::ItemNFE");
    ExceptionResponse exceptionResponse = new ExceptionResponse("Item Not Found Ex!!!", new Date(), webRequest.getDescription(false));
    ResponseEntity<ExceptionResponse> responseEntity = new ResponseEntity<ExceptionResponse>(exceptionResponse, HttpStatus.NOT_FOUND);
    return responseEntity;
}

But when I am calling the above service from a spring MVC application using RestTemplate, It is returning a valid object if it exists.

If the requested object does not exist Restful service is returning the exception information but its not reaching the calling(spring MVC) application.

Spring MVC application calls Restful Web Service using Rest template

String url = "http://localhost:8080/ItemServices/items/validate/{itemId}";
ResponseEntity<Object> responseEntity = restTemplate.exchange(url, HttpMethod.GET, httpEntity, Object.class, uriParms);
int restCallStateCode = responseEntity.getStatusCodeValue();
like image 795
Abdul Avatar asked Sep 05 '18 11:09

Abdul


People also ask

How do I set exceptions in ResponseEntity?

You have to provide implementation to use your error handler, map the response to response entity and throw the exception. Create new error exception class with ResponseEntity field. Custom error handler which maps the error response back to ResponseEntity.

What is ResponseEntity exception handler?

ResponseEntity<Object> handleException(Exception ex, WebRequest request) Provides handling for standard Spring MVC exceptions. protected ResponseEntity<Object> handleExceptionInternal(Exception ex, Object body, HttpHeaders headers, HttpStatus status, WebRequest request)

What is the return type of ResponseEntity?

A ResponseEntity is returned. We give ResponseEntity a custom status code, headers, and a body. With @ResponseBody , only the body is returned. The headers and status code are provided by Spring.

How do you handle exceptions in Spring boot?

Exception HandlerThe @ExceptionHandler is an annotation used to handle the specific exceptions and sending the custom responses to the client. Define a class that extends the RuntimeException class. You can define the @ExceptionHandler method to handle the exceptions as shown.


2 Answers

This is expected behavior. Rest template throws exception when the http status is client error or server error and returns the response when http status is not error status.

You have to provide implementation to use your error handler, map the response to response entity and throw the exception.

Create new error exception class with ResponseEntity field.

public class ResponseEntityErrorException extends RuntimeException {
  private ResponseEntity<ErrorResponse> errorResponse;
  public ResponseEntityErrorException(ResponseEntity<ErrorResponse> errorResponse) {
      this.errorResponse = errorResponse;
  }
  public ResponseEntity<ErrorResponse> getErrorResponse() {
      return errorResponse;
  }
}

Custom error handler which maps the error response back to ResponseEntity.

public class ResponseEntityErrorHandler implements ResponseErrorHandler {

  private List<HttpMessageConverter<?>> messageConverters;

  @Override
  public boolean hasError(ClientHttpResponse response) throws IOException {
    return hasError(response.getStatusCode());
  }

  protected boolean hasError(HttpStatus statusCode) {
    return (statusCode.is4xxClientError() || statusCode.is5xxServerError());
  }

  @Override
  public void handleError(ClientHttpResponse response) throws IOException {
    HttpMessageConverterExtractor<ExceptionResponse> errorMessageExtractor =
      new HttpMessageConverterExtractor(ExceptionResponse.class, messageConverters);
    ExceptionResponse errorObject = errorMessageExtractor.extractData(response);
    throw new ResponseEntityErrorException(ResponseEntity.status(response.getRawStatusCode()).headers(response.getHeaders()).body(errorObject));
  }

  public void setMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
    this.messageConverters = messageConverters;
  }
}

RestTemplate Configuration - You have to set RestTemplate's errorHandler to ResponseEntityErrorHandler.

@Configuration
public class RestTemplateConfiguration {
  @Bean
  public RestTemplate restTemplate() {
      RestTemplate restTemplate = new RestTemplate();
      ResponseEntityErrorHandler errorHandler = new ResponseEntityErrorHandler();
      errorHandler.setMessageConverters(restTemplate.getMessageConverters());
      restTemplate.setErrorHandler(errorHandler); 
      return restTemplate;
   }
}

Calling Method

@Autowired restTemplate

String url = "http://localhost:8080/ItemServices/items/validate/{itemId}";
try {
    ResponseEntity<Object> responseEntity = restTemplate.exchange(url, HttpMethod.GET, httpEntity, Object.class, uriParms);
    int restCallStateCode = responseEntity.getStatusCodeValue();
} catch (ResponseEntityErrorException re) {
    ResponseEntity<ErrorResponse> errorResponse = re.getErrorResponse();
}
like image 118
s7vr Avatar answered Nov 07 '22 21:11

s7vr


Try using the @ResponseBody annotation on your Exceptionhandler. e.g:

public @ResponseBody ResponseEntity<ExceptionResponse> itemNotFEx(WebRequest webRequest, Exception exception) {... }
like image 21
Otto Touzil Avatar answered Nov 07 '22 19:11

Otto Touzil