6

I try to catch exception wich I received from another microservice connected by FeignClient. I've made custom ErrorDecoder, and

public class CustomErrorDecoder implements ErrorDecoder {

    private final Logger log = LoggerFactory.getLogger(getClass());

    private final ErrorDecoder defaultErrorDecoder = new Default();

    @Override
    public Exception decode(String methodKey, Response response) {

        if (response.status() >= 400 && response.status() <= 499) {
            log.info("----------------- "+methodKey+" , "+response.status()+" , "+ response.reason());
            return new RestApiException(99,99,"");
        }
        return defaultErrorDecoder.decode(methodKey, response);
    }
} 

Where RestApiException extends Exception.

@ControllerAdvice
public class GlobalControllerAdvice {

    private final Logger log = LoggerFactory.getLogger(getClass());

    @ExceptionHandler(RestApiException.class)
    public ResponseEntity<RestApiException> handleException(RestApiException exception, HttpServletRequest req) {
        log.error("Sending error to client ( "+req.getUserPrincipal().getName()+" ) \"{}\"", exception.getErrMsg());
        return new ResponseEntity<RestApiException>(exception, exception.getStatus());
    }

    @ExceptionHandler(Throwable.class)
    public ResponseEntity<RestApiException> handleException(Throwable throwable, HttpServletRequest req) {
        RestApiException exception=new RestApiException(HttpStatus.INTERNAL_SERVER_ERROR, 100, 100,
                throwable.getMessage());
        return handleException(exception, req);
    }

As a result, when I get <--- HTTP/1.1 400 Bad Request (5380ms) I've got default error messages

HttpStatus.INTERNAL_SERVER_ERROR, 100, 100, throwable.getMessage());

but not expexted custom exception, which I try to set in CustomErrorDecoder.

What I'm doing wrong, why I can't call RetAppiException and return error answer to rest client.

Thanks.

koa73
  • 861
  • 2
  • 10
  • 27
  • Because you are calling the same method over and over... You are calling the `handleException(throwable)` method over and over. The other method has a different signature `handleException(exception, request)` but you aren't calling that. – M. Deinum Nov 01 '16 at 14:48
  • I think the main reason is (RestApiException.java:25) ~[classes/:na]., if I block this call code (@ExceptionHandler(Throwable.class)), I get the same error without ciclong call. – koa73 Nov 02 '16 at 08:23
  • No it isn't... Your issue really is that you are calling the same method over and over. – M. Deinum Nov 02 '16 at 08:31
  • I've add extra info in question. – koa73 Nov 02 '16 at 08:54
  • I give up. You are clearly calling the same method over and over, no matter how much information you provide, that still is happening. – M. Deinum Nov 02 '16 at 08:56
  • I've saw my mistake, Thanks. But anyway ControllerAdvice catch HystrixRuntimeException but not custom FeignClientException – koa73 Nov 02 '16 at 10:51

2 Answers2

10

You can't catch the exception of the FeignClient with a @ControllerAdvice. The exception handler will not catch the exceptions generated by the feign client, error decoder..

A simple solution would be catch your feign calls, and then throw the exception you want.

try{
   feignClient.method();
} catch(Exception ex){
  //throw exceptions you want
  throw new YourException();
}

Then you'll be able to handle it:

@ControllerAdvice
public class GlobalControllerAdvice {

    private final Logger log = LoggerFactory.getLogger(getClass());

    @ExceptionHandler(YourException.class)
    public ResponseEntity<RestApiException> handleException(RestApiException exception, HttpServletRequest req) {
        //impl
    }

}
Pau
  • 14,917
  • 14
  • 67
  • 94
  • 2
    Unfortunately not. Feign Client exception overwritten by HystrixRuntimeException so I lost first exception reason which I can catch and recognise into CustomErrorDecoder. So, @ControllerAdvice catch all exception very nice, but only HystrixRuntimeException. Your decision catch HystrixRuntimeException too. – koa73 Nov 02 '16 at 13:46
  • I didn't know you were using `Hystrix`, then it's easier. – Pau Nov 02 '16 at 13:49
  • This is not entirely true, because you can catch the `FeignException` as seen in https://stackoverflow.com/a/56241143/4567511 – dnl.re Jan 15 '20 at 17:49
0

You can catch feign client exceptions by catching HystrixRuntimeException and casting the getCause() to FeignClientException.

Example:

@ExceptionHandler
public ResponseEntity<Problem> handleFeignException(HystrixRuntimeException ex, NativeWebRequest request) {
    final FeignException.FeignClientException feignClientException = (FeignException.FeignClientException) ex.getCause();
    return handleException(feignClientException, request);
}