Overview
Two follow-up improvements deferred from #319 (PR #323) to keep that change focused. Both relate to making 422 Unprocessable Entity handling more robust and consistent.
1. GlobalExceptionHandler — Return structured validation errors
Current behaviour: handleValidationException returns an empty 422 body (ResponseEntity<Void>).
Proposed improvement:
- Build a response body from
exception.getBindingResult() — either a ProblemDetail (RFC 9457, available since Spring 6 / Spring Boot 3) or a Map<String, String> of field → message.
- Add SLF4J logging of the violations for observability.
Example sketch:
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ProblemDetail> handleValidationException(MethodArgumentNotValidException exception) {
log.warn("Validation failed: {}", exception.getBindingResult().getAllErrors());
ProblemDetail problem = ProblemDetail.forStatus(HttpStatus.UNPROCESSABLE_ENTITY);
problem.setDetail("Validation failed");
Map<String, String> errors = exception.getBindingResult().getFieldErrors().stream()
.collect(Collectors.toMap(FieldError::getField, FieldError::getDefaultMessage));
problem.setProperty("errors", errors);
return ResponseEntity.unprocessableEntity().body(problem);
}
2. PlayersController.put — Delegate squad number mismatch to validation
Current behaviour: The inline mismatch check returns 422 directly inside the controller method, bypassing GlobalExceptionHandler.
Proposed improvement:
- Introduce a cross-field constraint on
PlayerDTO (e.g., a custom @SquadNumberMatch annotation), or
- Throw a custom exception (e.g.,
SquadNumberMismatchException) and map it in GlobalExceptionHandler,
so that all 422 responses flow through a single, consistent handler.
References
Overview
Two follow-up improvements deferred from #319 (PR #323) to keep that change focused. Both relate to making
422 Unprocessable Entityhandling more robust and consistent.1.
GlobalExceptionHandler— Return structured validation errorsCurrent behaviour:
handleValidationExceptionreturns an empty422body (ResponseEntity<Void>).Proposed improvement:
exception.getBindingResult()— either aProblemDetail(RFC 9457, available since Spring 6 / Spring Boot 3) or aMap<String, String>of field → message.Example sketch:
2.
PlayersController.put— Delegate squad number mismatch to validationCurrent behaviour: The inline mismatch check returns
422directly inside the controller method, bypassingGlobalExceptionHandler.Proposed improvement:
PlayerDTO(e.g., a custom@SquadNumberMatchannotation), orSquadNumberMismatchException) and map it inGlobalExceptionHandler,so that all
422responses flow through a single, consistent handler.References
422 Unprocessable Entityfor payload validation errors #319