Kotlin - Spring REST - ControllerAdvice с ExceptionHandler не вызывается

Чтобы упростить обработку ошибок, мне нужен ExceptionHandler, я использовал точку 4. на http://www.baeldung.com/exception-handling-for-rest-with-spring.

Мой класс обработчика исключений выглядит следующим образом:

@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 - это простой Exception, расширяющий RuntimeException

class TestException : RuntimeException()

Во всяком случае, в моем RestController я просто бросаю исключение, как только делается любой вызов:

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

Но обработчик исключений не вызывается.

Однако вызывая это:

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

он вызывается.

Я не совсем понимаю, в чем разница, кроме первой версии, ожидающей параметров и определенного заголовка.

ОБНОВЛЕНИЕ 24.03.2018

Проблема, похоже, в том, что ExceptionHandler не вызывается, если запрос клиентов был искажен.

По умолчанию искаженный запрос приводит к довольно подробному отчету об ошибке, но пользовательский ExceptionHandler, похоже, отключает эту функцию.

Когда вы вызываете closeLobby(), видите ли вы исключение в журналах?

Todd 24.03.2018 18:25

Нет, я ничего не вижу.

Marcel 24.03.2018 18:29

Какой HTTP-ответ вы получите? 404?

Todd 24.03.2018 18:30

Я получаю 400 ответов. Однако это не из-за моего исключения, потому что я получаю 400, даже если я поменяю его там.

Marcel 24.03.2018 18:30

Похоже, вы просто неправильно делаете запрос. Что произойдет, если вы удалите исключение и вернете правильное значение?

Todd 24.03.2018 18:40

@Todd, вы правы, это не работает, только если запрос искажен, но в любом случае обработчик исключений не должен нарушать все остальные случаи обработки исключений, не так ли?

Marcel 24.03.2018 19:08
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
4
6
10 210
2

Ответы 2

На данный момент у меня есть решение, хотя я думаю, что это не должно быть желаемым способом.

Поскольку у моих контроллеров в любом случае не было базового класса, я не создавал BaseController, который содержит функции, обрабатывающие исключения, эти функции просто аннотируются с помощью ExceptionHandler, а их список методов содержит Exception, которые они должны обрабатывать.

Поскольку класс BasicController не расширяет какой-либо другой класс Spring, который обрабатывает исключения, он не отменяет поведение по умолчанию для обработки таких проблем, как искаженные запросы.

Я с радостью принимаю любое лучшее решение, потому что не думаю, что это должно быть желаемым способом.

У меня все заработало, вот мой код.

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

Класс исключения

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

Класс данных

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

Я пробовал это, он работает ТОЛЬКО, если мне нужно обрабатывать определенные исключения. Он терпит неудачу, как только у меня есть 2 метода, один для пользовательских исключений и один для общих исключений. Всякий раз, когда создавалось определяемое пользователем исключение, оно перехватывалось методом, аннотированным @ExceptionHandler(Exception::class), а не @ExceptionHandler(UserAlreadyExistsException::class). Какие-нибудь решения? Когда я попробовал это в java, он работал как шарм, но не в котлине.

Abhishek Saxena 20.11.2020 09:16

Я не знаю, есть ли какая-то конкретная ошибка, связанная с котином, в этом случае попробуйте расширить поиск

silentsudo 20.11.2020 10:16

Другие вопросы по теме