Marcel
Marcel

Reputation: 1594

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.

Upvotes: 7

Views: 19137

Answers (3)

Fernando Gabrieli
Fernando Gabrieli

Reputation: 1010

Please read here: https://newbedev.com/setting-precedence-of-multiple-controlleradvice-exceptionhandlers

regarding:

@ControllerAdvice
@Order(Ordered.HIGHEST_PRECEDENCE)

and

@ControllerAdvice
@Order(Ordered.LOWEST_PRECEDENCE)

You can combine these to handle more specific exceptions first

Upvotes: 0

silentsudo
silentsudo

Reputation: 6973

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)
    }

Upvotes: 13

Marcel
Marcel

Reputation: 1594

For now i have a solution, even though this shouldn't be the desired way i think.

Since my controllers had no base class anyways, i have no created a BaseController that contains functions that handle the Exceptions, those functions are simply annotated with ExceptionHandler and their method list contains the Exception they should handle.

Since the BasicController class doesn't extend any other Spring class that handles exceptions, it doesn't override the default behaviour for handling problems like malformed requests.

I gladly accept any better solution, because i don't think this should be the desired way.

Upvotes: 0

Related Questions