Reputation: 1594
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
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
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
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