I have the following comparison between 2 fields and if the comparison result is less than zero, I need to throw exception with a message like "Amount cannot be less than balance"
.
I think MethodArgumentNotValidException
is a proper type for this scenario. However, MethodArgumentNotValidException
does not take a message parameter:
public void transfer(Request request) {
if(sender.getBalance().compareTo(account.getAmount()) < 0)
throw new MethodArgumentNotValidException(MESSAGE);
// ...
}
So, should I implement a custom error class as shown below? I have also a Global Exception Handler class and this kind of custom classes for "Element Not found"
or "Element already exists"
.
public class CustomMethodArgumentNotValidException extends RuntimeException {
public MethodArgumentNotValidException() {
super();
}
public NoSuchElementFoundException(String message) {
super(message);
}
}
And then use add this custom exception to my Global Exception Handler? Or should I directly use it without any custom implementation as extra?
Update:
@RestControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
@Override
@ResponseStatus(HttpStatus.UNPROCESSABLE_ENTITY)
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex,
HttpHeaders headers,
HttpStatusCode statusCode,
WebRequest request) {
ErrorResponse errorResponse = new ErrorResponse(HttpStatus.UNPROCESSABLE_ENTITY.value(), VALIDATION_ERROR);
for (FieldError fieldError : ex.getBindingResult().getFieldErrors()) {
errorResponse.addValidationError(fieldError.getField(), fieldError.getDefaultMessage());
}
return ResponseEntity.unprocessableEntity().body(errorResponse);
}
@ExceptionHandler(NoSuchElementFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public ResponseEntity<Object> handleNoSuchElementFoundException(NoSuchElementFoundException ex, WebRequest request) {
return buildErrorResponse(ex, HttpStatus.NOT_FOUND, request);
}
@ExceptionHandler(InsufficientFundsException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ResponseEntity<Object> handleMethodArgumentInvalidException(InsufficientFundsException ex, WebRequest request) {
return buildErrorResponse(ex, HttpStatus.BAD_REQUEST, request);
}
@ExceptionHandler(AuthenticationException.class)
@ResponseStatus(HttpStatus.UNAUTHORIZED)
public ResponseEntity<Object> handleAuthenticationException(AuthenticationException ex, WebRequest request) {
return buildErrorResponse(ex, HttpStatus.UNAUTHORIZED, request);
}
@ExceptionHandler(Exception.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public ResponseEntity<Object> handleAllUncaughtException(Exception ex, WebRequest request) {
return buildErrorResponse(ex, UNKNOWN_ERROR, HttpStatus.INTERNAL_SERVER_ERROR, request);
}
private ResponseEntity<Object> buildErrorResponse(Exception ex,
HttpStatusCode statusCode,
WebRequest request) {
return buildErrorResponse(ex, ex.getMessage(), statusCode, request);
}
private ResponseEntity<Object> buildErrorResponse(Exception ex,
String message,
HttpStatusCode statusCode,
WebRequest request) {
final ErrorResponse errorResponse = new ErrorResponse(statusCode.value(), message);
if (printStackTrace && isTraceOn(request)) {
errorResponse.setStackTrace(ExceptionUtils.getStackTrace(ex));
}
return ResponseEntity.status(statusCode).body(errorResponse);
}
private boolean isTraceOn(WebRequest request) {
String[] value = request.getParameterValues(TRACE); // TRACE from app properties
return Objects.nonNull(value)
&& value.length > 0
&& value[0].contentEquals("true");
}
@Override
public ResponseEntity<Object> handleExceptionInternal(
Exception ex,
Object body,
HttpHeaders headers,
HttpStatusCode statusCode,
WebRequest request) {
return buildErrorResponse(ex, statusCode, request);
}
}
public class InsufficientFundsException extends RuntimeException {
public InsufficientFundsException() {
super();
}
public InsufficientFundsException(String message) {
super(message);
}
public InsufficientFundsException(String message, Throwable cause) {
super(message, cause);
}
}