Skip to content

Instantly share code, notes, and snippets.

@rommansabbir
Created October 16, 2021 06:46
Show Gist options
  • Save rommansabbir/97dc3df0ce5e6bce2ef795c4441b1180 to your computer and use it in GitHub Desktop.
Save rommansabbir/97dc3df0ce5e6bce2ef795c4441b1180 to your computer and use it in GitHub Desktop.
Handle API exception in Spring Boot
@ControllerAdvice
class APIExceptionHandler {
companion object {
/**
* Register all kind of Exceptions here
*/
private var exceptionListHolder: MutableMap<Class<*>, HttpStatus> = HashMap<Class<*>, HttpStatus>().apply {
put(NullPointerException::class.java, HttpStatus.NOT_FOUND)
put(NoSuchElementException::class.java, HttpStatus.NOT_FOUND)
put(MethodArgumentTypeMismatchException::class.java, HttpStatus.BAD_REQUEST)
put(MethodNotAllowedException::class.java, HttpStatus.BAD_REQUEST)
put(HttpRequestMethodNotSupportedException::class.java, HttpStatus.BAD_REQUEST)
put(NoHandlerFoundException::class.java, HttpStatus.NOT_FOUND)
put(IllegalArgumentException::class.java, HttpStatus.CONFLICT)
put(IllegalStateException::class.java, HttpStatus.CONFLICT)
put(HttpMediaTypeNotSupportedException::class.java, HttpStatus.UNSUPPORTED_MEDIA_TYPE)
put(HttpMediaTypeNotAcceptableException::class.java, HttpStatus.NOT_ACCEPTABLE)
put(MissingPathVariableException::class.java, HttpStatus.INTERNAL_SERVER_ERROR)
put(MissingServletRequestParameterException::class.java, HttpStatus.BAD_REQUEST)
put(ServletRequestBindingException::class.java, HttpStatus.BAD_REQUEST)
put(ConversionNotSupportedException::class.java, HttpStatus.INTERNAL_SERVER_ERROR)
put(TypeMismatchException::class.java, HttpStatus.BAD_REQUEST)
put(HttpMessageNotReadableException::class.java, HttpStatus.BAD_REQUEST)
put(HttpMessageNotWritableException::class.java, HttpStatus.INTERNAL_SERVER_ERROR)
put(MethodArgumentNotValidException::class.java, HttpStatus.BAD_REQUEST)
put(MissingServletRequestPartException::class.java, HttpStatus.BAD_REQUEST)
put(BindException::class.java, HttpStatus.BAD_REQUEST)
put(AsyncRequestTimeoutException::class.java, HttpStatus.SERVICE_UNAVAILABLE)
}
}
/**
* Handle API exception here.
* Initialize the [APIResponse] object with error status & message.
* Find the exception from the [exceptionListHolder] list else register [Exception] as a fallback.
* Map the error with [HttpStatus] code to custom exception object [APIException].
*
* Handle try catch, if any exception occur throw [HttpStatus.INTERNAL_SERVER_ERROR] with custom response object [APIResponse]
*
* @param exception, [Throwable] that need to be handled
*
* @return [ResponseEntity]
*/
@ExceptionHandler(Throwable::class)
@ResponseBody
fun handleException(exception: Throwable): ResponseEntity<APIResponse<*>> {
val response = APIResponse<Any>(status = false, message = "Error", data = null)
return try {
var status = exceptionListHolder[exception.javaClass]
if (status == null) {
status = exceptionListHolder[Exception::class.java]
}
response.apply {
error.add(APIException(status!!.value(), exception.message ?: APIErrors.GENERIC_ERROR_MESSAGE))
}
println(response)
ResponseEntity(response, status!!)
} catch (e: Exception) {
response.apply {
error.add(
APIException(
HttpStatus.INTERNAL_SERVER_ERROR.value(),
exception.message ?: APIErrors.GENERIC_ERROR_MESSAGE
)
)
}
println(response)
ResponseEntity(response, HttpStatus.INTERNAL_SERVER_ERROR)
}
}
}
// Define custom errors here
object APIErrors {
internal const val GENERIC_ERROR_MESSAGE = "Something went wrong."
}
// Custom exception class for API response
data class APIException(val errorCode: Int, val message: String)
// Custom response body for all API's
data class APIResponse<T>(
val status: Boolean = true,
val message: String,
val data: T?,
val error: MutableList<APIException> = mutableListOf()
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment