A violation throws MethodArgumentNotValidException → 400 before your method runs.
Annotation
Checks
@NotNull / @NotBlank / @NotEmpty
present / non-blank text / non-empty collection
@Size(min, max)
length or size
@Min / @Max / @Positive
numbers
@Email / @Pattern
format
@Past / @Future
dates
Validate parameters too:
@Validated// on the class@GetMapping("/search")List<Book>search(@RequestParam@NotBlankStringq){…}
Your own exceptions
publicclassBookNotFoundExceptionextendsRuntimeException{publicBookNotFoundException(longid){super("No book with id "+id);}}
One place for error responses
@RestControllerAdvicepublicclassApiExceptionHandler{@ExceptionHandler(BookNotFoundException.class)ProblemDetailnotFound(BookNotFoundExceptionex){varpd=ProblemDetail.forStatusAndDetail(HttpStatus.NOT_FOUND,ex.getMessage());pd.setTitle("Book not found");returnpd;}@ExceptionHandler(MethodArgumentNotValidException.class)ProblemDetailinvalid(MethodArgumentNotValidExceptionex){varpd=ProblemDetail.forStatus(HttpStatus.BAD_REQUEST);pd.setTitle("Validation failed");pd.setProperty("errors",ex.getBindingResult().getFieldErrors().stream().collect(toMap(FieldError::getField,FieldError::getDefaultMessage)));returnpd;}}
@RestControllerAdvice applies to every controller.
RFC 9457 problem details
ProblemDetail is the standard error format:
{"type":"about:blank","title":"Book not found","status":404,"detail":"No book with id 42","instance":"/api/books/42"}
Turn it on for the framework’s own errors too:
spring.mvc.problemdetails.enabled=true
Shortcut for simple cases
thrownewResponseStatusException(HttpStatus.NOT_FOUND,"No book with id "+id);
Fine in small apps; a typed exception plus advice scales better.
Warning
Never return the stack trace to clients. Log it with the request id and send the client a
short message.