From 82771754f1169888c62f9c7fd9cd3867065d3ff2 Mon Sep 17 00:00:00 2001 From: Alexander Dudkin Date: Wed, 25 Sep 2024 23:42:21 +0300 Subject: [PATCH] refactor: switch to rest controller advice --- .../advice/GlobalRestExceptionHandler.java | 49 +++++++++++++++ .../rest/advice/RestControllerAdvice.java | 48 --------------- .../advice/GlobalRestExceptionHandler.java | 54 ++++++++++++++++ .../rest/advice/RestControllerAdvice.java | 61 ------------------- .../advice/GlobalExceptionHandler.java | 5 +- .../advice/GlobalRestExceptionHandler.java | 48 +++++++++++++++ .../rest/advice/RestControllerAdvice.java | 47 -------------- .../advice/GlobalRestExceptionHandler.java | 51 ++++++++++++++++ .../rest/advice/RestControllerAdvice.java | 47 -------------- .../advice/GlobalRestExceptionHandler.java | 1 - 10 files changed, 204 insertions(+), 207 deletions(-) create mode 100644 library-api-authentication-server/src/main/java/dev/earlspilner/auth/rest/advice/GlobalRestExceptionHandler.java delete mode 100644 library-api-authentication-server/src/main/java/dev/earlspilner/auth/rest/advice/RestControllerAdvice.java create mode 100644 library-api-books-service/src/main/java/dev/earlspilner/books/rest/advice/GlobalRestExceptionHandler.java delete mode 100644 library-api-books-service/src/main/java/dev/earlspilner/books/rest/advice/RestControllerAdvice.java create mode 100644 library-api-library-service/src/main/java/dev/earlspilner/library/rest/advice/GlobalRestExceptionHandler.java delete mode 100644 library-api-library-service/src/main/java/dev/earlspilner/library/rest/advice/RestControllerAdvice.java create mode 100644 library-api-loan-service/src/main/java/dev/earlspilner/loans/rest/advice/GlobalRestExceptionHandler.java delete mode 100644 library-api-loan-service/src/main/java/dev/earlspilner/loans/rest/advice/RestControllerAdvice.java diff --git a/library-api-authentication-server/src/main/java/dev/earlspilner/auth/rest/advice/GlobalRestExceptionHandler.java b/library-api-authentication-server/src/main/java/dev/earlspilner/auth/rest/advice/GlobalRestExceptionHandler.java new file mode 100644 index 0000000..5a9adab --- /dev/null +++ b/library-api-authentication-server/src/main/java/dev/earlspilner/auth/rest/advice/GlobalRestExceptionHandler.java @@ -0,0 +1,49 @@ +package dev.earlspilner.auth.rest.advice; + +import dev.earlspilner.auth.rest.advice.custom.BadUserCredentialsException; +import dev.earlspilner.auth.rest.advice.custom.CustomJwtException; +import org.springframework.http.HttpStatus; +import org.springframework.http.ProblemDetail; +import org.springframework.http.ResponseEntity; +import org.springframework.security.core.userdetails.UsernameNotFoundException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import static org.springframework.http.HttpStatus.*; + +/** + * @author Alexander Dudkin + */ +@RestControllerAdvice +public class GlobalRestExceptionHandler { + + private static final Map, HttpStatus> exceptionStatusMap = new ConcurrentHashMap<>(); + + static { + exceptionStatusMap.put(CustomJwtException.class, UNAUTHORIZED); + exceptionStatusMap.put(BadUserCredentialsException.class, BAD_REQUEST); + exceptionStatusMap.put(UsernameNotFoundException.class, NOT_FOUND); + } + + @ExceptionHandler({ + CustomJwtException.class, + BadUserCredentialsException.class, + UsernameNotFoundException.class, + }) + public ResponseEntity handleException(Exception e) { + HttpStatus status = exceptionStatusMap.getOrDefault(e.getClass(), INTERNAL_SERVER_ERROR); + ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(status, e.getMessage()); + return ResponseEntity.status(status).body(problemDetail); + } + + @ExceptionHandler(Exception.class) + public ResponseEntity handleGenericException(Exception e) { + HttpStatus status = INTERNAL_SERVER_ERROR; + ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(status, "An unexpected error occurred. Please try again later."); + return ResponseEntity.status(status).body(problemDetail); + } + +} diff --git a/library-api-authentication-server/src/main/java/dev/earlspilner/auth/rest/advice/RestControllerAdvice.java b/library-api-authentication-server/src/main/java/dev/earlspilner/auth/rest/advice/RestControllerAdvice.java deleted file mode 100644 index 8278d97..0000000 --- a/library-api-authentication-server/src/main/java/dev/earlspilner/auth/rest/advice/RestControllerAdvice.java +++ /dev/null @@ -1,48 +0,0 @@ -package dev.earlspilner.auth.rest.advice; - -import dev.earlspilner.auth.rest.advice.custom.BadUserCredentialsException; -import dev.earlspilner.auth.rest.advice.custom.CustomJwtException; -import org.springframework.http.HttpStatus; -import org.springframework.http.ProblemDetail; -import org.springframework.http.ResponseEntity; -import org.springframework.security.core.userdetails.UsernameNotFoundException; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ExceptionHandler; - -import static org.springframework.http.HttpStatus.*; - -/** - * @author Alexander Dudkin - */ -@ControllerAdvice -public class RestControllerAdvice { - - @ExceptionHandler(Exception.class) - public ResponseEntity handleException(Exception e) { - ProblemDetail problemDetail = createProblemDetail(INTERNAL_SERVER_ERROR, e.getMessage()); - return ResponseEntity.status(INTERNAL_SERVER_ERROR).body(problemDetail); - } - - @ExceptionHandler(CustomJwtException.class) - public ResponseEntity handleCustomJwtException(CustomJwtException e) { - ProblemDetail problemDetail = createProblemDetail(e.getHttpStatus(), e.getMessage()); - return ResponseEntity.status(e.getHttpStatus()).body(problemDetail); - } - - @ExceptionHandler(BadUserCredentialsException.class) - public ResponseEntity handleBadUserCredentialsException(BadUserCredentialsException e) { - ProblemDetail problemDetail = createProblemDetail(BAD_REQUEST, e.getMessage()); - return ResponseEntity.status(BAD_REQUEST).body(problemDetail); - } - - @ExceptionHandler(UsernameNotFoundException.class) - public ResponseEntity handleIllegalArgumentException(IllegalArgumentException e) { - ProblemDetail problemDetail = createProblemDetail(NOT_FOUND, e.getMessage()); - return ResponseEntity.status(NOT_FOUND).body(problemDetail); - } - - private ProblemDetail createProblemDetail(HttpStatus status, String title) { - return ProblemDetail.forStatusAndDetail(status, title); - } - -} diff --git a/library-api-books-service/src/main/java/dev/earlspilner/books/rest/advice/GlobalRestExceptionHandler.java b/library-api-books-service/src/main/java/dev/earlspilner/books/rest/advice/GlobalRestExceptionHandler.java new file mode 100644 index 0000000..2753646 --- /dev/null +++ b/library-api-books-service/src/main/java/dev/earlspilner/books/rest/advice/GlobalRestExceptionHandler.java @@ -0,0 +1,54 @@ +package dev.earlspilner.books.rest.advice; + +import dev.earlspilner.books.rest.advice.custom.BookExistsException; +import dev.earlspilner.books.rest.advice.custom.BookNotFoundException; +import dev.earlspilner.books.rest.advice.custom.UnauthorizedOperationException; +import org.springframework.http.HttpStatus; +import org.springframework.http.ProblemDetail; +import org.springframework.http.ResponseEntity; +import org.springframework.security.authorization.AuthorizationDeniedException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import static org.springframework.http.HttpStatus.*; + +/** + * @author Alexander Dudkin + */ +@RestControllerAdvice +public class GlobalRestExceptionHandler { + + private static final Map, HttpStatus> exceptionStatusMap = new ConcurrentHashMap<>(); + + static { + exceptionStatusMap.put(UnauthorizedOperationException.class, UNAUTHORIZED); + exceptionStatusMap.put(AuthorizationDeniedException.class, FORBIDDEN); + exceptionStatusMap.put(BookExistsException.class, BAD_REQUEST); + exceptionStatusMap.put(BookNotFoundException.class, NOT_FOUND); + exceptionStatusMap.put(IllegalArgumentException.class, BAD_REQUEST); + } + + @ExceptionHandler({ + UnauthorizedOperationException.class, + AuthorizationDeniedException.class, + BookExistsException.class, + BookNotFoundException.class, + IllegalArgumentException.class, + }) + public ResponseEntity handleException(Exception e) { + HttpStatus status = exceptionStatusMap.getOrDefault(e.getClass(), INTERNAL_SERVER_ERROR); + ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(status, e.getMessage()); + return ResponseEntity.status(status).body(problemDetail); + } + + @ExceptionHandler(Exception.class) + public ResponseEntity handleGenericException(Exception e) { + HttpStatus status = INTERNAL_SERVER_ERROR; + ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(status, "An unexpected error occurred. Please try again later."); + return ResponseEntity.status(status).body(problemDetail); + } + +} diff --git a/library-api-books-service/src/main/java/dev/earlspilner/books/rest/advice/RestControllerAdvice.java b/library-api-books-service/src/main/java/dev/earlspilner/books/rest/advice/RestControllerAdvice.java deleted file mode 100644 index 2ee2dc8..0000000 --- a/library-api-books-service/src/main/java/dev/earlspilner/books/rest/advice/RestControllerAdvice.java +++ /dev/null @@ -1,61 +0,0 @@ -package dev.earlspilner.books.rest.advice; - -import dev.earlspilner.books.rest.advice.custom.BookExistsException; -import dev.earlspilner.books.rest.advice.custom.BookNotFoundException; -import dev.earlspilner.books.rest.advice.custom.UnauthorizedOperationException; -import org.springframework.http.HttpStatus; -import org.springframework.http.ProblemDetail; -import org.springframework.http.ResponseEntity; -import org.springframework.security.authorization.AuthorizationDeniedException; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ExceptionHandler; - -import static org.springframework.http.HttpStatus.*; - -/** - * @author Alexander Dudkin - */ -@ControllerAdvice -public class RestControllerAdvice { - - @ExceptionHandler(Exception.class) - public ResponseEntity handleException(Exception e) { - ProblemDetail problemDetail = createProblemDetail(INTERNAL_SERVER_ERROR, e.getMessage()); - return ResponseEntity.status(INTERNAL_SERVER_ERROR).body(problemDetail); - } - - @ExceptionHandler(UnauthorizedOperationException.class) - public ResponseEntity handleUnauthorizedOperationException(UnauthorizedOperationException e) { - ProblemDetail problemDetail = createProblemDetail(HttpStatus.UNAUTHORIZED, e.getMessage()); - return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(problemDetail); - } - - @ExceptionHandler(AuthorizationDeniedException.class) - public ResponseEntity handleAuthorizationDeniedException(AuthorizationDeniedException e) { - ProblemDetail problemDetail = createProblemDetail(HttpStatus.FORBIDDEN, e.getMessage()); - return ResponseEntity.status(FORBIDDEN).body(problemDetail); - } - - @ExceptionHandler(BookExistsException.class) - public ResponseEntity handleBookExistsException(BookExistsException e) { - ProblemDetail problemDetail = createProblemDetail(BAD_REQUEST, e.getMessage()); - return ResponseEntity.status(BAD_REQUEST).body(problemDetail); - } - - @ExceptionHandler(BookNotFoundException.class) - public ResponseEntity handleBookNotFoundException(BookNotFoundException e) { - ProblemDetail problemDetail = createProblemDetail(NOT_FOUND, e.getMessage()); - return ResponseEntity.status(NOT_FOUND).body(problemDetail); - } - - @ExceptionHandler(IllegalArgumentException.class) - public ResponseEntity handleIllegalArgumentException(IllegalArgumentException e) { - ProblemDetail problemDetail = createProblemDetail(BAD_REQUEST, e.getMessage()); - return ResponseEntity.status(BAD_REQUEST).body(problemDetail); - } - - private ProblemDetail createProblemDetail(HttpStatus status, String title) { - return ProblemDetail.forStatusAndDetail(status, title); - } - -} diff --git a/library-api-gateway/src/main/java/dev/earlspilner/gateway/advice/GlobalExceptionHandler.java b/library-api-gateway/src/main/java/dev/earlspilner/gateway/advice/GlobalExceptionHandler.java index 3a8c8f8..0da37b2 100644 --- a/library-api-gateway/src/main/java/dev/earlspilner/gateway/advice/GlobalExceptionHandler.java +++ b/library-api-gateway/src/main/java/dev/earlspilner/gateway/advice/GlobalExceptionHandler.java @@ -1,11 +1,10 @@ package dev.earlspilner.gateway.advice; -import org.springframework.http.ProblemDetail; -import org.springframework.web.bind.annotation.RestControllerAdvice; import io.jsonwebtoken.ExpiredJwtException; -import org.springframework.http.HttpStatus; +import org.springframework.http.ProblemDetail; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; diff --git a/library-api-library-service/src/main/java/dev/earlspilner/library/rest/advice/GlobalRestExceptionHandler.java b/library-api-library-service/src/main/java/dev/earlspilner/library/rest/advice/GlobalRestExceptionHandler.java new file mode 100644 index 0000000..3a4e239 --- /dev/null +++ b/library-api-library-service/src/main/java/dev/earlspilner/library/rest/advice/GlobalRestExceptionHandler.java @@ -0,0 +1,48 @@ +package dev.earlspilner.library.rest.advice; + +import dev.earlspilner.library.rest.advice.custom.BookRecordNotFoundException; +import dev.earlspilner.library.rest.advice.custom.UnauthorizedOperationException; +import org.springframework.http.HttpStatus; +import org.springframework.http.ProblemDetail; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import static org.springframework.http.HttpStatus.*; + +/** + * @author Alexander Dudkin + */ +@RestControllerAdvice +public class GlobalRestExceptionHandler { + + private static final Map, HttpStatus> exceptionStatusMap = new ConcurrentHashMap<>(); + + static { + exceptionStatusMap.put(UnauthorizedOperationException.class, UNAUTHORIZED); + exceptionStatusMap.put(BookRecordNotFoundException.class, NOT_FOUND); + exceptionStatusMap.put(IllegalArgumentException.class, BAD_REQUEST); + } + + @ExceptionHandler({ + UnauthorizedOperationException.class, + BookRecordNotFoundException.class, + IllegalArgumentException.class + }) + public ResponseEntity handleException(Exception e) { + HttpStatus status = exceptionStatusMap.getOrDefault(e.getClass(), INTERNAL_SERVER_ERROR); + ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(status, e.getMessage()); + return ResponseEntity.status(status).body(problemDetail); + } + + @ExceptionHandler(Exception.class) + public ResponseEntity handleGenericException(Exception e) { + HttpStatus status = INTERNAL_SERVER_ERROR; + ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(status, "An unexpected error occurred. Please try again later."); + return ResponseEntity.status(status).body(problemDetail); + } + +} diff --git a/library-api-library-service/src/main/java/dev/earlspilner/library/rest/advice/RestControllerAdvice.java b/library-api-library-service/src/main/java/dev/earlspilner/library/rest/advice/RestControllerAdvice.java deleted file mode 100644 index 8f452a4..0000000 --- a/library-api-library-service/src/main/java/dev/earlspilner/library/rest/advice/RestControllerAdvice.java +++ /dev/null @@ -1,47 +0,0 @@ -package dev.earlspilner.library.rest.advice; - -import dev.earlspilner.library.rest.advice.custom.BookRecordNotFoundException; -import dev.earlspilner.library.rest.advice.custom.UnauthorizedOperationException; -import org.springframework.http.HttpStatus; -import org.springframework.http.ProblemDetail; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ExceptionHandler; - -import static org.springframework.http.HttpStatus.*; - -/** - * @author Alexander Dudkin - */ -@ControllerAdvice -public class RestControllerAdvice { - - @ExceptionHandler(Exception.class) - public ResponseEntity handleException(Exception e) { - ProblemDetail problemDetail = createProblemDetail(INTERNAL_SERVER_ERROR, e.getMessage()); - return ResponseEntity.status(INTERNAL_SERVER_ERROR).body(problemDetail); - } - - @ExceptionHandler(UnauthorizedOperationException.class) - public ResponseEntity handleUnauthorizedOperationException(UnauthorizedOperationException e) { - ProblemDetail problemDetail = createProblemDetail(HttpStatus.UNAUTHORIZED, e.getMessage()); - return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(problemDetail); - } - - @ExceptionHandler(BookRecordNotFoundException.class) - public ResponseEntity handleBookRecordNotFoundException(BookRecordNotFoundException e) { - ProblemDetail problemDetail = createProblemDetail(NOT_FOUND, e.getMessage()); - return ResponseEntity.status(NOT_FOUND).body(problemDetail); - } - - @ExceptionHandler(IllegalArgumentException.class) - public ResponseEntity handleIllegalArgumentException(IllegalArgumentException e) { - ProblemDetail problemDetail = createProblemDetail(BAD_REQUEST, e.getMessage()); - return ResponseEntity.status(BAD_REQUEST).body(problemDetail); - } - - private ProblemDetail createProblemDetail(HttpStatus status, String title) { - return ProblemDetail.forStatusAndDetail(status, title); - } - -} diff --git a/library-api-loan-service/src/main/java/dev/earlspilner/loans/rest/advice/GlobalRestExceptionHandler.java b/library-api-loan-service/src/main/java/dev/earlspilner/loans/rest/advice/GlobalRestExceptionHandler.java new file mode 100644 index 0000000..186829e --- /dev/null +++ b/library-api-loan-service/src/main/java/dev/earlspilner/loans/rest/advice/GlobalRestExceptionHandler.java @@ -0,0 +1,51 @@ +package dev.earlspilner.loans.rest.advice; + +import dev.earlspilner.loans.rest.advice.custom.LoanNotFoundException; +import dev.earlspilner.loans.rest.advice.custom.UnauthorizedOperationException; +import org.springframework.http.HttpStatus; +import org.springframework.http.ProblemDetail; +import org.springframework.http.ResponseEntity; +import org.springframework.security.authorization.AuthorizationDeniedException; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import static org.springframework.http.HttpStatus.*; + +/** + * @author Alexander Dudkin + */ +@RestControllerAdvice +public class GlobalRestExceptionHandler { + + private static final Map, HttpStatus> exceptionStatusMap = new ConcurrentHashMap<>(); + + static { + exceptionStatusMap.put(UnauthorizedOperationException.class, UNAUTHORIZED); + exceptionStatusMap.put(AuthorizationDeniedException.class, FORBIDDEN); + exceptionStatusMap.put(UnsupportedOperationException.class, UNPROCESSABLE_ENTITY); + exceptionStatusMap.put(LoanNotFoundException.class, NOT_FOUND); + } + + @ExceptionHandler({ + UnauthorizedOperationException.class, + AuthorizationDeniedException.class, + UnsupportedOperationException.class, + LoanNotFoundException.class + }) + public ResponseEntity handleException(Exception e) { + HttpStatus status = exceptionStatusMap.getOrDefault(e.getClass(), INTERNAL_SERVER_ERROR); + ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(status, e.getMessage()); + return ResponseEntity.status(status).body(problemDetail); + } + + @ExceptionHandler(Exception.class) + public ResponseEntity handleGenericException(Exception e) { + HttpStatus status = INTERNAL_SERVER_ERROR; + ProblemDetail problemDetail = ProblemDetail.forStatusAndDetail(status, "An unexpected error occurred. Please try again later."); + return ResponseEntity.status(status).body(problemDetail); + } + +} diff --git a/library-api-loan-service/src/main/java/dev/earlspilner/loans/rest/advice/RestControllerAdvice.java b/library-api-loan-service/src/main/java/dev/earlspilner/loans/rest/advice/RestControllerAdvice.java deleted file mode 100644 index f6ab2eb..0000000 --- a/library-api-loan-service/src/main/java/dev/earlspilner/loans/rest/advice/RestControllerAdvice.java +++ /dev/null @@ -1,47 +0,0 @@ -package dev.earlspilner.loans.rest.advice; - -import dev.earlspilner.loans.rest.advice.custom.LoanNotFoundException; -import dev.earlspilner.loans.rest.advice.custom.UnauthorizedOperationException; -import org.springframework.http.HttpStatus; -import org.springframework.http.ProblemDetail; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.ControllerAdvice; -import org.springframework.web.bind.annotation.ExceptionHandler; - -import static org.springframework.http.HttpStatus.*; - -/** - * @author Alexander Dudkin - */ -@ControllerAdvice -public class RestControllerAdvice { - - @ExceptionHandler(Exception.class) - public ResponseEntity handleException(Exception e) { - ProblemDetail problemDetail = createProblemDetail(INTERNAL_SERVER_ERROR, e.getMessage()); - return ResponseEntity.status(INTERNAL_SERVER_ERROR).body(problemDetail); - } - - @ExceptionHandler(UnauthorizedOperationException.class) - public ResponseEntity handleUnauthorizedOperationException(UnauthorizedOperationException e) { - ProblemDetail problemDetail = createProblemDetail(HttpStatus.UNAUTHORIZED, e.getMessage()); - return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body(problemDetail); - } - - @ExceptionHandler(LoanNotFoundException.class) - public ResponseEntity handleLoanNotFoundException(LoanNotFoundException e) { - ProblemDetail problemDetail = createProblemDetail(NOT_FOUND, e.getMessage()); - return ResponseEntity.status(NOT_FOUND).body(problemDetail); - } - - @ExceptionHandler(UnsupportedOperationException.class) - public ResponseEntity handleUnsupportedOperationException(UnsupportedOperationException e) { - ProblemDetail problemDetail = createProblemDetail(UNPROCESSABLE_ENTITY, e.getMessage()); - return ResponseEntity.status(UNPROCESSABLE_ENTITY).body(problemDetail); - } - - private ProblemDetail createProblemDetail(HttpStatus status, String title) { - return ProblemDetail.forStatusAndDetail(status, title); - } - -} diff --git a/library-api-users-service/src/main/java/dev/earlspilner/users/rest/advice/GlobalRestExceptionHandler.java b/library-api-users-service/src/main/java/dev/earlspilner/users/rest/advice/GlobalRestExceptionHandler.java index 678394f..a12fd3f 100644 --- a/library-api-users-service/src/main/java/dev/earlspilner/users/rest/advice/GlobalRestExceptionHandler.java +++ b/library-api-users-service/src/main/java/dev/earlspilner/users/rest/advice/GlobalRestExceptionHandler.java @@ -1,6 +1,5 @@ package dev.earlspilner.users.rest.advice; -import dev.earlspilner.users.rest.advice.custom.CustomJwtException; import dev.earlspilner.users.rest.advice.custom.UnauthorizedOperationException; import dev.earlspilner.users.rest.advice.custom.UserExistsException; import dev.earlspilner.users.rest.advice.custom.UserNotFoundException;