ExceptionController.java
package com.distasilucas.cryptobalancetracker.controller;
import com.distasilucas.cryptobalancetracker.exception.ApiException;
import com.distasilucas.cryptobalancetracker.exception.ApiValidationException;
import com.distasilucas.cryptobalancetracker.exception.CoingeckoCryptoNotFoundException;
import com.distasilucas.cryptobalancetracker.exception.DuplicatedCryptoPlatFormException;
import com.distasilucas.cryptobalancetracker.exception.DuplicatedGoalException;
import com.distasilucas.cryptobalancetracker.exception.DuplicatedPlatformException;
import com.distasilucas.cryptobalancetracker.exception.GoalNotFoundException;
import com.distasilucas.cryptobalancetracker.exception.InsufficientBalanceException;
import com.distasilucas.cryptobalancetracker.exception.PlatformNotFoundException;
import com.distasilucas.cryptobalancetracker.exception.TooManyRequestsException;
import com.distasilucas.cryptobalancetracker.exception.UserCryptoNotFoundException;
import com.distasilucas.cryptobalancetracker.exception.UsernameNotFoundException;
import jakarta.validation.ConstraintViolationException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.ProblemDetail;
import org.springframework.http.ResponseEntity;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import java.net.URI;
import java.util.Arrays;
import java.util.List;
import static com.distasilucas.cryptobalancetracker.constants.Constants.UNKNOWN_ERROR;
import static com.distasilucas.cryptobalancetracker.constants.ExceptionConstants.INVALID_VALUE_FOR;
@Slf4j
@RestControllerAdvice
public class ExceptionController {
private static final HttpStatus NOT_FOUND_STATUS = HttpStatus.NOT_FOUND;
private static final HttpStatus BAD_REQUEST_STATUS = HttpStatus.BAD_REQUEST;
@ExceptionHandler(PlatformNotFoundException.class)
public ResponseEntity<List<ProblemDetail>> handlePlatformNotFoundException(
PlatformNotFoundException exception,
WebRequest webRequest
) {
log.info("A PlatformNotFoundException has occurred", exception);
var request = (ServletWebRequest) webRequest;
var problemDetail = ProblemDetail.forStatusAndDetail(NOT_FOUND_STATUS, exception.getMessage());
problemDetail.setType(URI.create(request.getRequest().getRequestURL().toString()));
return ResponseEntity.status(NOT_FOUND_STATUS).body(List.of(problemDetail));
}
@ExceptionHandler(DuplicatedPlatformException.class)
public ResponseEntity<List<ProblemDetail>> handleDuplicatedPlatformException(
DuplicatedPlatformException exception,
WebRequest webRequest
) {
log.info("A DuplicatedPlatformException has occurred", exception);
var request = (ServletWebRequest) webRequest;
var problemDetail = ProblemDetail.forStatusAndDetail(BAD_REQUEST_STATUS, exception.getMessage());
problemDetail.setType(URI.create(request.getRequest().getRequestURL().toString()));
return ResponseEntity.status(BAD_REQUEST_STATUS).body(List.of(problemDetail));
}
@ExceptionHandler(GoalNotFoundException.class)
public ResponseEntity<List<ProblemDetail>> handleGoalNotFoundException(
GoalNotFoundException exception,
WebRequest webRequest
) {
log.info("A GoalNotFoundException has occurred", exception);
var request = (ServletWebRequest) webRequest;
var problemDetail = ProblemDetail.forStatusAndDetail(NOT_FOUND_STATUS, exception.getMessage());
problemDetail.setType(URI.create(request.getRequest().getRequestURL().toString()));
return ResponseEntity.status(NOT_FOUND_STATUS).body(List.of(problemDetail));
}
@ExceptionHandler(DuplicatedGoalException.class)
public ResponseEntity<List<ProblemDetail>> handleDuplicatedGoalException(
DuplicatedGoalException exception,
WebRequest webRequest
) {
log.info("A DuplicatedGoalException has occurred", exception);
var request = (ServletWebRequest) webRequest;
var problemDetail = ProblemDetail.forStatusAndDetail(BAD_REQUEST_STATUS, exception.getMessage());
problemDetail.setType(URI.create(request.getRequest().getRequestURL().toString()));
return ResponseEntity.status(BAD_REQUEST_STATUS).body(List.of(problemDetail));
}
@ExceptionHandler(CoingeckoCryptoNotFoundException.class)
public ResponseEntity<List<ProblemDetail>> handleCoingeckoCryptoNotFoundException(
CoingeckoCryptoNotFoundException exception,
WebRequest webRequest
) {
log.info("A CoingeckoCryptoNotFoundException has occurred", exception);
var request = (ServletWebRequest) webRequest;
var problemDetail = ProblemDetail.forStatusAndDetail(NOT_FOUND_STATUS, exception.getMessage());
problemDetail.setType(URI.create(request.getRequest().getRequestURL().toString()));
return ResponseEntity.status(NOT_FOUND_STATUS).body(List.of(problemDetail));
}
@ExceptionHandler(DuplicatedCryptoPlatFormException.class)
public ResponseEntity<List<ProblemDetail>> handleDuplicatedCryptoPlatFormException(
DuplicatedCryptoPlatFormException exception,
WebRequest webRequest
) {
log.info("A DuplicatedCryptoPlatFormException has occurred", exception);
var request = (ServletWebRequest) webRequest;
var problemDetail = ProblemDetail.forStatusAndDetail(BAD_REQUEST_STATUS, exception.getMessage());
problemDetail.setType(URI.create(request.getRequest().getRequestURL().toString()));
return ResponseEntity.status(BAD_REQUEST_STATUS).body(List.of(problemDetail));
}
@ExceptionHandler(UserCryptoNotFoundException.class)
public ResponseEntity<List<ProblemDetail>> handleUserCryptoNotFoundException(
UserCryptoNotFoundException exception,
WebRequest webRequest
) {
log.info("An UserCryptoNotFoundException has occurred", exception);
var request = (ServletWebRequest) webRequest;
var problemDetail = ProblemDetail.forStatusAndDetail(NOT_FOUND_STATUS, exception.getMessage());
problemDetail.setType(URI.create(request.getRequest().getRequestURL().toString()));
return ResponseEntity.status(NOT_FOUND_STATUS).body(List.of(problemDetail));
}
@ExceptionHandler(TooManyRequestsException.class)
public ResponseEntity<List<ProblemDetail>> handleTooManyRequestsException(
TooManyRequestsException exception,
WebRequest webRequest
) {
log.info("A TooManyRequestsException has occurred", exception);
var request = (ServletWebRequest) webRequest;
var problemDetail = ProblemDetail.forStatusAndDetail(HttpStatus.TOO_MANY_REQUESTS, exception.getMessage());
problemDetail.setType(URI.create(request.getRequest().getRequestURL().toString()));
return ResponseEntity.status(HttpStatus.TOO_MANY_REQUESTS).body(List.of(problemDetail));
}
@ExceptionHandler(InsufficientBalanceException.class)
public ResponseEntity<List<ProblemDetail>> handleInsufficientBalanceException(
InsufficientBalanceException exception,
WebRequest webRequest
) {
log.info("An InsufficientBalanceException has occurred", exception);
var request = (ServletWebRequest) webRequest;
var problemDetail = ProblemDetail.forStatusAndDetail(HttpStatus.BAD_REQUEST, exception.getMessage());
problemDetail.setType(URI.create(request.getRequest().getRequestURL().toString()));
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(List.of(problemDetail));
}
@ExceptionHandler(UsernameNotFoundException.class)
public ResponseEntity<List<ProblemDetail>> handleUsernameNotFoundException(
UsernameNotFoundException exception,
WebRequest webRequest
) {
log.info("An UsernameNotFoundException has occurred", exception);
var request = (ServletWebRequest) webRequest;
var problemDetail = ProblemDetail.forStatusAndDetail(NOT_FOUND_STATUS, exception.getMessage());
problemDetail.setType(URI.create(request.getRequest().getRequestURL().toString()));
return ResponseEntity.status(NOT_FOUND_STATUS).body(List.of(problemDetail));
}
@ExceptionHandler(ApiValidationException.class)
public ResponseEntity<List<ProblemDetail>> handleApiValidationException(
ApiValidationException exception,
WebRequest webRequest
) {
log.info("An ApiValidationException has occurred", exception);
var request = (ServletWebRequest) webRequest;
var problemDetail = ProblemDetail.forStatusAndDetail(exception.getHttpStatus(), exception.getMessage());
problemDetail.setType(URI.create(request.getRequest().getRequestURL().toString()));
return ResponseEntity.status(exception.getHttpStatus()).body(List.of(problemDetail));
}
@ExceptionHandler(ApiException.class)
public ResponseEntity<List<ProblemDetail>> handleApiException(
ApiException exception,
WebRequest webRequest
) {
log.info("An ApiException has occurred", exception);
var request = (ServletWebRequest) webRequest;
var problemDetail = ProblemDetail.forStatusAndDetail(exception.getHttpStatus(), exception.getMessage());
problemDetail.setType(URI.create(request.getRequest().getRequestURL().toString()));
return ResponseEntity.status(exception.getHttpStatus()).body(List.of(problemDetail));
}
@ExceptionHandler(ConstraintViolationException.class)
public ResponseEntity<List<ProblemDetail>> handleConstraintViolationException(
ConstraintViolationException exception,
WebRequest webRequest
) {
log.info("A ConstraintViolationException has occurred", exception);
var request = (ServletWebRequest) webRequest;
var constraintViolations = exception.getConstraintViolations().stream().toList();
var problemDetails = constraintViolations.stream()
.map(constraintViolation -> {
var problemDetail = ProblemDetail.forStatusAndDetail(BAD_REQUEST_STATUS, constraintViolation.getMessage());
problemDetail.setType(URI.create(request.getRequest().getRequestURL().toString()));
return problemDetail;
})
.toList();
return ResponseEntity.status(BAD_REQUEST_STATUS).body(problemDetails);
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<List<ProblemDetail>> handleMethodArgumentNotValidException(
MethodArgumentNotValidException exception,
WebRequest webRequest
) {
log.info("A MethodArgumentNotValidException has occurred", exception);
var request = (ServletWebRequest) webRequest;
var allErrors = exception.getAllErrors()
.stream()
.map(error -> {
var errorMessage = StringUtils.hasText(error.getDefaultMessage()) ? error.getDefaultMessage() : UNKNOWN_ERROR;
var problemDetail = ProblemDetail.forStatusAndDetail(BAD_REQUEST_STATUS, errorMessage);
problemDetail.setType(URI.create(request.getRequest().getRequestURL().toString()));
return problemDetail;
})
.toList();
return ResponseEntity.status(BAD_REQUEST_STATUS).body(allErrors);
}
@ExceptionHandler(MissingServletRequestParameterException.class)
public ResponseEntity<List<ProblemDetail>> handleMissingServletRequestParameterException(
MissingServletRequestParameterException exception,
WebRequest webRequest
) {
log.info("A MissingServletRequestParameterException has occurred", exception);
var request = (ServletWebRequest) webRequest;
var bodyDetail = exception.getBody().getDetail();
var detail = StringUtils.hasText(bodyDetail) ? bodyDetail : exception.getMessage();
var problemDetail = ProblemDetail.forStatusAndDetail(BAD_REQUEST_STATUS, detail);
problemDetail.setType(URI.create(request.getRequest().getRequestURL().toString()));
return ResponseEntity.status(BAD_REQUEST_STATUS).body(List.of(problemDetail));
}
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
public ResponseEntity<List<ProblemDetail>> handleMethodArgumentTypeMismatchException(
MethodArgumentTypeMismatchException exception,
WebRequest webRequest
) {
log.info("A MethodArgumentTypeMismatchException has occurred", exception);
var name = exception.getName();
var message = String.format("Invalid value %s for %s", exception.getValue(), name);
var requiredType = exception.getRequiredType();
if (requiredType != null) {
var availableValues = Arrays.toString(requiredType.getEnumConstants());
message = String.format(INVALID_VALUE_FOR, exception.getValue(), name, availableValues);
}
var request = (ServletWebRequest) webRequest;
var problemDetail = ProblemDetail.forStatusAndDetail(BAD_REQUEST_STATUS, message);
problemDetail.setType(URI.create(request.getRequest().getRequestURL().toString()));
return ResponseEntity.status(BAD_REQUEST_STATUS).body(List.of(problemDetail));
}
@ExceptionHandler(Exception.class)
public ResponseEntity<List<ProblemDetail>> handleException(
Exception exception,
WebRequest webRequest
) {
log.error("An unhandled Exception has occurred", exception);
var request = (ServletWebRequest) webRequest;
var problemDetail = ProblemDetail.forStatusAndDetail(HttpStatus.INTERNAL_SERVER_ERROR, UNKNOWN_ERROR);
problemDetail.setType(URI.create(request.getRequest().getRequestURL().toString()));
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(List.of(problemDetail));
}
}