ApiExceptionHandler.java
3,048 bytes
| 1 | package com.tasteprint.shared; |
|---|---|
| 2 | |
| 3 | import java.net.URI; |
| 4 | import java.util.LinkedHashMap; |
| 5 | import java.util.Map; |
| 6 | |
| 7 | import jakarta.validation.ConstraintViolationException; |
| 8 | |
| 9 | import org.springframework.dao.DataIntegrityViolationException; |
| 10 | import org.springframework.http.HttpStatus; |
| 11 | import org.springframework.http.ProblemDetail; |
| 12 | import org.springframework.security.core.AuthenticationException; |
| 13 | import org.springframework.web.bind.MethodArgumentNotValidException; |
| 14 | import org.springframework.web.bind.annotation.ExceptionHandler; |
| 15 | import org.springframework.web.bind.annotation.RestControllerAdvice; |
| 16 | |
| 17 | @RestControllerAdvice |
| 18 | class ApiExceptionHandler { |
| 19 | |
| 20 | @ExceptionHandler(NotFoundException.class) |
| 21 | ProblemDetail handleNotFound(NotFoundException exception) { |
| 22 | return problem(HttpStatus.NOT_FOUND, "Resource not found", exception.getMessage()); |
| 23 | } |
| 24 | |
| 25 | @ExceptionHandler(ConflictException.class) |
| 26 | ProblemDetail handleConflict(ConflictException exception) { |
| 27 | return problem(HttpStatus.CONFLICT, "Conflict", exception.getMessage()); |
| 28 | } |
| 29 | |
| 30 | @ExceptionHandler(ForbiddenException.class) |
| 31 | ProblemDetail handleForbidden(ForbiddenException exception) { |
| 32 | return problem(HttpStatus.FORBIDDEN, "Forbidden", exception.getMessage()); |
| 33 | } |
| 34 | |
| 35 | @ExceptionHandler(AuthenticationException.class) |
| 36 | ProblemDetail handleAuthentication(AuthenticationException exception) { |
| 37 | return problem(HttpStatus.UNAUTHORIZED, "Authentication failed", exception.getMessage()); |
| 38 | } |
| 39 | |
| 40 | @ExceptionHandler(MethodArgumentNotValidException.class) |
| 41 | ProblemDetail handleValidation(MethodArgumentNotValidException exception) { |
| 42 | ProblemDetail detail = problem(HttpStatus.BAD_REQUEST, "Validation failed", "Check the highlighted fields."); |
| 43 | Map<String, String> errors = new LinkedHashMap<>(); |
| 44 | exception.getBindingResult().getFieldErrors().forEach(error -> |
| 45 | errors.putIfAbsent(error.getField(), error.getDefaultMessage())); |
| 46 | detail.setProperty("errors", errors); |
| 47 | return detail; |
| 48 | } |
| 49 | |
| 50 | @ExceptionHandler(ConstraintViolationException.class) |
| 51 | ProblemDetail handleConstraintViolation(ConstraintViolationException exception) { |
| 52 | return problem(HttpStatus.BAD_REQUEST, "Validation failed", exception.getMessage()); |
| 53 | } |
| 54 | |
| 55 | @ExceptionHandler(DataIntegrityViolationException.class) |
| 56 | ProblemDetail handleIntegrityViolation() { |
| 57 | return problem(HttpStatus.CONFLICT, "Conflict", "That change conflicts with existing data."); |
| 58 | } |
| 59 | |
| 60 | @ExceptionHandler(IllegalArgumentException.class) |
| 61 | ProblemDetail handleIllegalArgument(IllegalArgumentException exception) { |
| 62 | return problem(HttpStatus.BAD_REQUEST, "Invalid request", exception.getMessage()); |
| 63 | } |
| 64 | |
| 65 | private ProblemDetail problem(HttpStatus status, String title, String detail) { |
| 66 | ProblemDetail problem = ProblemDetail.forStatusAndDetail(status, detail); |
| 67 | problem.setTitle(title); |
| 68 | problem.setType(URI.create("https://tasteprint.app/problems/" + status.value())); |
| 69 | return problem; |
| 70 | } |
| 71 | } |
| 72 | |