https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#howto.application.failure-analyzer https://docs.spring.io/spring-boot/docs/3.2.2/api/org/springframework/boot/diagnostics/FailureAnalyzer.html https://docs.spring.io/spring-boot/docs/3.2.2/api/org/springframework/boot/diagnostics/FailureAnalysis.html baeldung https://www.baeldung.com/exception-handling-for-rest-with-spring 2024 Otus - Exceptions from Java to Spring 1:55:00 of 2:15:46 https://www.youtube.com/watch?v=dsSFmPeUezY ! 15:00 - hierarchy BusyCoderAcademy - 5. Spring Boot Rest Project Employee Mgt Application with Ex handling Validation||Rajeev Gupta of 1:31:30 https://www.youtube.com/watch?v=XTk6fz1i9UA ! package for exceptions ! 44:00 proper way is to create separate @RestControllerAdvice EmployeeAppExHandlerController ! create @Data ErrorInfo // dto ... import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; ... @RestControllerAdvice public class EmployeeAppExHandlerController { @ExceptionHandler public ResponseEntity handle4042(EmployeeNotFoundException e) { var errorInfo = ErrorInfo.builder() .errorMessage(e.getMessage()) .timeStamp(LocalDateTime.now()) .toContact("firs.last@yopmail.com") .statusCode(HttpStatus.NOT_FOUND.toString()) .build(); return ResponseEntity.status(HttpStatus.NOT_FOUND) .body(errorInfo); } } ! ! add spring-boot-starter-validation ! Dto-classes to transfer data between controller/service layer ! GenerateAllSetter idea plugin to convert one objecto into the other ! Entity-Corruption pattern - controller-layer should not talk to entities ! @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity handle400(MethodArgumentNotValidException e) { String errorMessage = e.getBindingResult().getAllErrors().stream().map(e -> e.getDefaultMessage()) ... } src/main/resources/ValidationMessages.properties employeeDto.name.absent=... employeeDto.email.absent=... public class EmployeeDto { ... @NotEmpty(message="{employeeDto.name.absent}") private String name; @Email(message="...") private String email; ... } 2023 https://blog.stackademic.com/mastering-exception-handling-in-spring-boot-33d74a1dfc9e https://dip-mazumder.medium.com/spring-boot-exception-handling-best-practices-e8ebe97e8ce 2021 https://dzone.com/articles/spring-boot-exception-handling https://github.com/SeunMatt/smattme-tutorials/tree/master/spring-boot-exception-handling 2020 https://reflectoring.io/spring-boot-exception-handling/ https://github.com/thombergs/code-examples/tree/master/spring-boot/exception-handling 2019 https://thepracticaldeveloper.com/2019/09/09/custom-error-handling-rest-controllers-spring-boot/ https://dzone.com/articles/spring-rest-service-exception-handling-1 2018 https://dzone.com/articles/customize-error-responses-in-spring-boot public enum ErrorMessages { MISSING_REQUIRED_FIELD("BlaBla..."), RECORD_ALREADY_EXISTS("AnotherBla...") private String errorMessage; public ErrorMessage(String errorMessage) { this.errorMessage = errorMessage; } public String getErrorMessage() { return errorMessage; } } public class UserRestController { @PostMapping(...) public User createUser(@RequestBody UserDetailsRequestModel userDetails) throws Exception { if () { throw new Exception(ErrorMessage.MISSING_REQUIRED_FIELD.getErrorMessage()); // { // "timestamp": "2018-05-09...", // "status": 500, // "error": "Internal Server Error", // "message": "BlaBla...", // "path": "/users" // } } } } package ...exception.UserServiceException; public class UserServiceException extend RuntimeException { private static final long serialVersionUID = 134l...L; public UserServiceException(String message) { super(message); } } public class UserRestController { @PostMapping(...) public User createUser(@RequestBody UserDetailsRequestModel userDetails) throws UserServiceException { if () { throw new UserServiceException(ErrorMessage.MISSING_REQUIRED_FIELD.getErrorMessage()); } } } package ...exceptions.AppExceptionsHandler; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ControllerAdvice; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.context.Request.WebRequest; @ControllerAdvice public class AppExceptionsHandler { @ExceptionHandler(value = {UserServiceException.class}) public ResponseEntity handleUserServiceException(UserServiceException ex, WebRequest request) { return new ResponseEntity<>(ex.getMessage, new HTTPHeaders(), HTTPStatus.INTERNAL_SERVER_ERROR); // no Accept headers } } public class ErrorMessage { private Date timestamp; private String errorMessage; public ErrorMessage() { } // getters/setters } @ControllerAdvice public class AppExceptionsHandler { @ExceptionHandler(value = {UserServiceException.class}) public ResponseEntity handleUserServiceException(UserServiceException ex, WebRequest request) { ErrorMessage errorMessage = new ErrorMessage(new Date(), ex.getMessage()); return new ResponseEntity<>(errorMessage, new HTTPHeaders(), HTTPStatus.INTERNAL_SERVER_ERROR); // now we can use headers } @ExceptionHandler(value = {Exception.class}) public ResponseEntity handleOtherException(Exception ex, WebRequest request) { ErrorMessage errorMessage = new ErrorMessage(new Date(), ex.getMessage()); return new ResponseEntity<>(errorMessage, new HTTPHeaders(), HTTPStatus.INTERNAL_SERVER_ERROR); } }