Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin - Spring REST - ControllerAdvice with ExceptionHandler won't get invoked

In order to simplify my error handling i wanted an ExceptionHandler, i have used the 4. point on http://www.baeldung.com/exception-handling-for-rest-with-spring .

My exception handler class looks like follows:

@ControllerAdvice
class APIExceptionHandler : ResponseEntityExceptionHandler() {

    @ExceptionHandler(value = [(TestException::class)])
    fun handleConflict(exception: TestException, request: WebRequest): ResponseEntity<Any> {
        println("Handle")
        return handleExceptionInternal(exception, "Response Body", HttpHeaders(), HttpStatus.BAD_REQUEST, request)
    }
}

TestException is just a simple Exception that extends RuntimeException

class TestException : RuntimeException()

Anyhow, in my RestController i am simply throwing an exception as soon as any call is made:

@GetMapping("/lobby/close")
fun closeLobby(@RequestParam(value = "uuid") uuid: String, @RequestHeader(value = "userSession") userSession: String): ResponseEntity<Any> {
    throw TestException()
}

But the exception handler is not invoked.

However, calling this:

@GetMapping("/lobby/error")
fun error(): ResponseEntity<Any> {
    throw TestException()
}

it is invoked.

I don't quite understand what the difference is, besides of the first version expecting parameters and a specific header.

UPDATE 24.03.2018

The problem seems to be, that the ExceptionHandler isn't being invoked if the clients request was malformed.

By default a malformed request leads to a pretty detailed error report, but the custom ExceptionHandler seems to disable this functionality.

like image 804
Marcel Avatar asked Mar 24 '18 17:03

Marcel


People also ask

How do I use ControllerAdvice in spring boot example?

Spring Boot @ControllerAdvice example. In the following Spring Boot application we use @ControllerAdvice to handle three exceptions: when a city is not found, when there is no data, and when a data for a new city to be saved is not valid. This is the project structure. This is the Gradle build file.

How do you handle DefaultHandlerExceptionResolver?

Class DefaultHandlerExceptionResolver. The default implementation of the HandlerExceptionResolver interface, resolving standard Spring MVC exceptions and translating them to corresponding HTTP status codes. This exception resolver is enabled by default in the common Spring DispatcherServlet .

What is the difference between ControllerAdvice and RestControllerAdvice?

The differences between @RestControllerAdvice and @ControllerAdvice is : @RestControllerAdvice = @ControllerAdvice + @ResponseBody . - we can use in REST web services. @ControllerAdvice - We can use in both MVC and Rest web services, need to provide the ResponseBody if we use this in Rest web services.


1 Answers

I got it working, here is my code.

@ControllerAdvice
class ControllerAdviceRequestError : ResponseEntityExceptionHandler() {
    @ExceptionHandler(value = [(UserAlreadyExistsException::class)])
    fun handleUserAlreadyExists(ex: UserAlreadyExistsException,request: WebRequest): ResponseEntity<ErrorsDetails> {
        val errorDetails = ErrorsDetails(Date(),
                "Validation Failed",
                ex.message!!
        )
        return ResponseEntity(errorDetails, HttpStatus.BAD_REQUEST)
    }
}

Exception class

class UserAlreadyExistsException(override val message: String?) : Exception(message)

Data class

data class ErrorsDetails(val time: Date, val message: String, val details: String)

MyController:

@PostMapping(value = ["/register"])
    fun register(@Valid @RequestBody user: User): User {
        if (userService.exists(user.username)) {
            throw UserAlreadyExistsException("User with username ${user.username} already exists")
        }
        return userService.create(user)
    }
like image 188
silentsudo Avatar answered Oct 13 '22 11:10

silentsudo