Rafael

Engenheiro de Software

Olá, Eu sou Rafael. Estou construindo coisas para a web e mobile.

Um desenvolvedor dedicado a criar experiências digitais de alto desempenho, acessíveis e limpas. Eu me especializo em transformar problemas complexos em soluções de engenharia elegantes.

ControllerAdvice como tratar Exception em spring boot e kotlin

O @ControllerAdvice no Spring Boot serve para centralizar o tratamento de exceções da aplicação. Em vez de colocar try/catch em todos os controllers e services, você lança uma exceção e o Spring encaminha automaticamente para a classe anotada com @ControllerAdvice.

Primeiramente vamos configurar o application.yml para não exibir dados com valores null na saída da resposta http, veja a opção jackson:

KOTLIN
spring:
  application:
    name: demo
  jpa:
    hibernate:
      ddl-auto: update
  datasource:
    url: jdbc:mysql://localhost:3306/mercadolivro?createDatabaseIfNotExist=true
    username: root
    password: root
  jackson:
    default-property-inclusion: non_null

Criando exceções customizadas

NotFoundException:

KOTLIN
class NotFoundException(
    override val message: String,
    val errorCode: String
) : Exception()

BadRequestException:

KOTLIN
class BadRequestException(
    override val message: String,
    val errorCode: String
) : Exception()

Criando o modelo de resposta de erro:

KOTLIN
data class ErrorResponse(
    var httpCode: Int,
    var message: String?,
    var internalCode: String,
    var erros: List<FieldErrorResponse>?
)

Nosso FieldErrorResponse:

KOTLIN
data class FieldErrorResponse(
    var message:String,
    var field:String
)

Nosso ENUM de erros:

KOTLIN
enum class Errors(val code: String, val message: String) {
    ML101("ML_101", "Book {%s} not exists"),
    ML102("ML_102", "Cannot update book with status {%s}"),
    ML201("ML_201", "Customer {%s} not exists"),
    ML301("ML_301", "UUID {%s} invalid")
}

Nosso controller advice para tratar os erros:

KOTLIN
@ControllerAdvice
class ControllerAdvice {
    @ExceptionHandler(NotFoundException::class)
    fun handlerNotFoundExpection(ex:NotFoundException,request:WebRequest):ResponseEntity<ErrorResponse>{
        val erro = ErrorResponse(
            httpCode = HttpStatus.NOT_FOUND.value(),
            message = ex.message,
            internalCode = ex.errorCode,
            erros = null
        )

        return ResponseEntity(erro, HttpStatus.NOT_FOUND)
    }
    @ExceptionHandler(BadResquetExpection::class)
    fun handlerBadRequestException(ex:BadResquetExpection,request:WebRequest):ResponseEntity<ErrorResponse>{
        val erro = ErrorResponse(
            httpCode = HttpStatus.BAD_REQUEST.value(),
            message = ex.message,
            internalCode = ex.errorCode,
            erros = null
        )

        return ResponseEntity(erro, HttpStatus.BAD_REQUEST)
    }

    @ExceptionHandler(MethodArgumentTypeMismatchException::class)
    fun handleArgumentTypeMismatch(
        ex: MethodArgumentTypeMismatchException
    ): ResponseEntity<ErrorResponse> {
        val valorInvalido = ex.value?.toString() ?: ""
        val error = ErrorResponse(
            httpCode = HttpStatus.BAD_REQUEST.value(),
            message = Errors.ML301.message.format(valorInvalido),
            internalCode = Errors.ML301.code,
            erros = null
        )

        return ResponseEntity(error, HttpStatus.BAD_REQUEST)
    }
}

Chamando o NotFound:

KOTLIN
repository.findById(id.toString()).orElseThrow{
            NotFoundException(Errors.ML101.message.format(id),Errors.ML101.code)
        }

A chamada do BadRequest seria similar mas com a classe de BadRequestException. No caso UUID inválido ele já pega o erro automaticamente.

Exemplos UUID:

HTTP
GET http://localhost:8080/book/2618f213-233e-405f-9216-da4496be0d1er

Saída:

JSON
{
    "httpCode": 400,
    "message": "UUID {2618f213-233e-405f-9216-da4496be0d1er} invalid",
    "internalCode": "ML_301"
}

Exemplo NotFound:

HTTP
GET ttp://localhost:8080/book/2618f213-233e-405f-9216-da4496be0d1

Saída:

JSON
{
    "httpCode": 404,
    "message": "Book {2618f213-233e-405f-9216-0da4496be0d1} not exists",
    "internalCode": "ML_101"
}

0 comentários

Deixe seu comentário