diff --git a/src/main/java/org/springframework/samples/petclinic/rest/advice/ExceptionControllerAdvice.java b/src/main/java/org/springframework/samples/petclinic/rest/advice/ExceptionControllerAdvice.java
index a49745d00..a01b1ebc8 100644
--- a/src/main/java/org/springframework/samples/petclinic/rest/advice/ExceptionControllerAdvice.java
+++ b/src/main/java/org/springframework/samples/petclinic/rest/advice/ExceptionControllerAdvice.java
@@ -18,6 +18,7 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
@@ -33,53 +34,76 @@
import static org.springframework.http.HttpStatus.BAD_REQUEST;
/**
+ * Global Exception handler for REST controllers.
+ *
+ * This class handles exceptions thrown by REST controllers and returns
+ * appropriate HTTP responses to the client.
+ *
* @author Vitaliy Fedoriv
+ * @author Alexander Dudkin
*/
-
@ControllerAdvice
public class ExceptionControllerAdvice {
- @ExceptionHandler(Exception.class)
- public ResponseEntity exception(Exception e) {
- ObjectMapper mapper = new ObjectMapper();
- ErrorInfo errorInfo = new ErrorInfo(e);
- String respJSONstring = "{}";
- try {
- respJSONstring = mapper.writeValueAsString(errorInfo);
- } catch (JsonProcessingException e1) {
- e1.printStackTrace();
+ /**
+ * Record for storing error information.
+ *
+ * This record encapsulates the class name and message of the exception.
+ *
+ * @param className The name of the exception class
+ * @param exMessage The message of the exception
+ */
+ private record ErrorInfo(String className, String exMessage) {
+ public ErrorInfo(Exception ex) {
+ this(ex.getClass().getName(), ex.getLocalizedMessage());
}
- return ResponseEntity.badRequest().body(respJSONstring);
+ }
+
+ /**
+ * Handles all general exceptions by returning a 500 Internal Server Error status with error details.
+ *
+ * @param e The exception to be handled
+ * @return A {@link ResponseEntity} containing the error information and a 500 Internal Server Error status
+ */
+ @ExceptionHandler(Exception.class)
+ public ResponseEntity handleGeneralException(Exception e) {
+ ErrorInfo info = new ErrorInfo(e);
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(info);
+ }
+
+ /**
+ * Handles {@link DataIntegrityViolationException} which typically indicates database constraint violations.
+ * This method returns a 404 Not Found status if an entity does not exist.
+ *
+ * @param ex The {@link DataIntegrityViolationException} to be handled
+ * @return A {@link ResponseEntity} containing the error information and a 404 Not Found status
+ */
+ @ExceptionHandler(DataIntegrityViolationException.class)
+ @ResponseStatus(code = HttpStatus.NOT_FOUND)
+ @ResponseBody
+ public ResponseEntity handleDataIntegrityViolationException(DataIntegrityViolationException ex) {
+ ErrorInfo errorInfo = new ErrorInfo(ex);
+ return ResponseEntity.status(HttpStatus.NOT_FOUND).body(errorInfo);
}
/**
* Handles exception thrown by Bean Validation on controller methods parameters
*
* @param ex The thrown exception
- * @param request the current web request
+ *
* @return an empty response entity
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
- @ResponseStatus(code = BAD_REQUEST)
+ @ResponseStatus(BAD_REQUEST)
@ResponseBody
- public ResponseEntity handleMethodArgumentNotValidException(MethodArgumentNotValidException ex, WebRequest request) {
+ public ResponseEntity handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
BindingErrorsResponse errors = new BindingErrorsResponse();
BindingResult bindingResult = ex.getBindingResult();
- HttpHeaders headers = new HttpHeaders();
if (bindingResult.hasErrors()) {
errors.addAllErrors(bindingResult);
- headers.add("errors", errors.toJSON());
+ return ResponseEntity.badRequest().body(new ErrorInfo("MethodArgumentNotValidException", "Validation failed"));
}
- return new ResponseEntity<>(headers, HttpStatus.BAD_REQUEST);
+ return ResponseEntity.badRequest().build();
}
- private class ErrorInfo {
- public final String className;
- public final String exMessage;
-
- public ErrorInfo(Exception ex) {
- this.className = ex.getClass().getName();
- this.exMessage = ex.getLocalizedMessage();
- }
- }
}
diff --git a/src/main/resources/openapi.yml b/src/main/resources/openapi.yml
index 162ef2754..86699c034 100755
--- a/src/main/resources/openapi.yml
+++ b/src/main/resources/openapi.yml
@@ -74,7 +74,7 @@ paths:
required: true
responses:
201:
- description: The pet owner was sucessfully added.
+ description: The pet owner was successfully added.
content:
application/json:
schema:
@@ -314,7 +314,7 @@ paths:
required: true
responses:
201:
- description: The pet was sucessfully added.
+ description: The pet was successfully added.
content:
application/json:
schema:
@@ -326,7 +326,7 @@ paths:
schema:
$ref: '#/components/schemas/RestError'
404:
- description: Pet not found.
+ description: Pet or Owner not found.
content:
application/json:
schema:
@@ -489,7 +489,7 @@ paths:
required: true
responses:
201:
- description: The vet visit was sucessfully added.
+ description: The vet visit was successfully added.
content:
application/json:
schema:
@@ -1849,7 +1849,7 @@ components:
readOnly: true
timestamp:
title: Timestamp
- description: The time the error occured.
+ description: The time the error occurred.
type: string
format: date-time
example: '2019-08-21T21:41:46.158+0000'
@@ -1886,7 +1886,7 @@ components:
properties:
message:
title: Message
- description: The valiation message.
+ description: The validation message.
type: string
example: "[Path '/lastName'] Instance type (null) does not match any allowed primitive type (allowed: [\"string\"])"
readOnly: true
diff --git a/src/test/java/org/springframework/samples/petclinic/rest/controller/PetRestControllerTests.java b/src/test/java/org/springframework/samples/petclinic/rest/controller/PetRestControllerTests.java
index 06f1b5a99..a4bce2b9f 100644
--- a/src/test/java/org/springframework/samples/petclinic/rest/controller/PetRestControllerTests.java
+++ b/src/test/java/org/springframework/samples/petclinic/rest/controller/PetRestControllerTests.java
@@ -241,7 +241,8 @@ void testAddPetError() throws Exception {
String newPetAsJSON = mapper.writeValueAsString(newPet);
given(this.clinicService.findPetById(999)).willReturn(null);
this.mockMvc.perform(post("/api/pets")
- .content(new String()).accept(MediaType.APPLICATION_JSON_VALUE).contentType(MediaType.APPLICATION_JSON_VALUE))
+ // set empty JSON to force 400 error
+ .content("{}").accept(MediaType.APPLICATION_JSON_VALUE).contentType(MediaType.APPLICATION_JSON_VALUE))
.andExpect(status().isBadRequest());
}
}
diff --git a/src/test/java/org/springframework/samples/petclinic/rest/controller/UserRestControllerTests.java b/src/test/java/org/springframework/samples/petclinic/rest/controller/UserRestControllerTests.java
index 9c5f504d6..ed65ee184 100644
--- a/src/test/java/org/springframework/samples/petclinic/rest/controller/UserRestControllerTests.java
+++ b/src/test/java/org/springframework/samples/petclinic/rest/controller/UserRestControllerTests.java
@@ -63,7 +63,7 @@ void testCreateUserSuccess() throws Exception {
@WithMockUser(roles = "ADMIN")
void testCreateUserError() throws Exception {
User user = new User();
- user.setUsername("username");
+ user.setUsername(""); // set empty username to force 400 error
user.setPassword("password");
user.setEnabled(true);
ObjectMapper mapper = new ObjectMapper();