Rajesh Varikuti
Rajesh Varikuti

Reputation: 21

Exception Handler not working on a spring boot app, @RestControllerAdvice is never been called and I am using low-level client

Trying to setup a global custom exception handling mechanism which relies on @RestControllerAdvice which can handle exceptions.

@RestControllerAdvice** exception handler not firing at all. Here, I am using low-level client.

I had the following controller advice set up, to return an APIs contract for error conditions:

I tried to add below

@ExceptionHandler(value = { ResponseException.class })
public ApiErrorResponse noHandlerFoundException(Exception ex) {
    LOG.error(ex.getCause().toString());
    int status = ((ResponseException) ex).getResponse().getStatusLine().getStatusCode();
    return new ApiErrorResponse(status, "<some message depending on status code>");
}

but seeing same result

pom.xml:

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.9.RELEASE</version>
    </parent>

    <properties>
        <java.version>1.8</java.version>
    </properties>

GlobalControllerExceptionHandler:

    @RestControllerAdvice
    public class GlobalControllerExceptionHandler extends ResponseEntityExceptionHandler{

        private static final Logger LOG = Logger.getLogger(GlobalControllerExceptionHandler.class);

        @ExceptionHandler(value = { ConstraintViolationException.class })
        @ResponseStatus(HttpStatus.BAD_REQUEST)
        public ApiErrorResponse constraintViolationException(ConstraintViolationException ex) {
            LOG.error(ex.getCause().toString());
            return new ApiErrorResponse(400, "Bad Request");
        }

        @ExceptionHandler(value = { NoHandlerFoundException.class })
        @ResponseStatus(HttpStatus.NOT_FOUND)
        public ApiErrorResponse noHandlerFoundException(Exception ex) {
            LOG.error(ex.getCause().toString());
            return new ApiErrorResponse(404, "Resource Not Found");
        }

        @ExceptionHandler(value = { Exception.class })
        @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
        public ApiErrorResponse unknownException(Exception ex) {
            LOG.error(ex.getCause().toString());
            return new ApiErrorResponse(500, "Internal Server Error");
        }
    }

ApiErrorResponse:

    public class ApiErrorResponse {

        private int status;
        private String message;

        public ApiErrorResponse(int status, String message) {
            this.status = status;
            this.message = message;
        }

        public int getStatus() {
            return status;
        }

        public String getMessage() {
            return message;
        }

        @Override
        public String toString() {
            return new ToStringBuilder(this).append(status)
                                            .append(message)
                                            .toString();
        }
    }

The problem with this is when I use a 3rd party library to do something.

Upvotes: 1

Views: 13609

Answers (2)

S34N
S34N

Reputation: 8371

It's due to the fact that you're trying to handle a nested exception via javax.validation.ConstraintViolationException; ConstraintViolationException is a nested exception of org.springframework.transaction.TransactionSystemException;

Change the handler to @ExceptionHandler(TransactionSystemException.class)

TransactionSystemException is not an ideal resolution, but it works. This bug is fixed in the latest version of Spring Boot version: >= 2.4.0

In the link below, you can see how they unwrapped the ConstraintViolationException

Unwrap ConstraintViolationException from TransactionSystemException

Alternatively you can upgrade to:

// Gradle Config
plugins {
    id 'org.springframework.boot' version '2.4.0'
    id 'io.spring.dependency-management' version '1.0.10.RELEASE'
    id 'java'
}

As of Spring Boot version: >= 2.4.0 you're now able to handle nested exceptions.

Upvotes: 1

Alien
Alien

Reputation: 15908

Make sure that your controller advice is being scanned.

For that, you can put your controller advice class in the inner package from the spring boot application main class so that spring boot will automatically scan all the inner packages.

Or

Try adding @EnableWebMvc annotation to your configuration class.

Refer this example

Upvotes: 2

Related Questions