I have a custom constraint validation done in my SpringBoot app (2.6.5) before an entity is persisted with JPA. When the validation causes a constraint violation the service used for persisting throws a TransactionSystemException. I can catch and format as needed this exception returned by REST API calls, with the following ExceptionHandler implementation:
@ControllerAdvice
public class RestResponseExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler({ TransactionSystemException.class })
public ResponseEntity<Object> handleTransactionSystemException(TransactionSystemException tse, WebRequest request) {
List<String> errors = null;
if (tse.getCause() instanceof RollbackException) {
var rollBack = (RollbackException) tse.getCause();
if (rollBack.getCause() instanceof ConstraintViolationException) {
var violation = (ConstraintViolationException) rollBack.getCause();
errors = this.buildValidationErrors(violation.getConstraintViolations());
}
}
var msg = "{message: 'The entity to persist was invalid'";
if (errors != null) {
msg += ", errors: " + errors;
}
msg += "}";
return new ResponseEntity<>(msg, new HttpHeaders(), HttpStatus.BAD_REQUEST);
}
private List<String> buildValidationErrors(Set<ConstraintViolation<?>> violations) {
return violations
.stream()
.map(violation -> "{field: '" + violation.getPropertyPath() + "', error: '" + violation.getMessage() + "'}")
.collect(Collectors.toList());
}
}
All works fine, but I'd like to know if the nasty checking of instances of the underlying causes in exceptions could be done better?
Ultimately the nicest thing would be to remove the @ExceptionHandler({ TransactionSystemException.class }) and replace it with @ExceptionHandler({ ConstraintViolationException.class }).
Is there a (simple) way to prevent TransactionsystemException from happening in between and just bubble up the ConstraintViolationException as is (so it can be caught by the ExceptionHandler)?