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 f98780cd..3911149d 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
@@ -16,6 +16,7 @@
package org.springframework.samples.petclinic.rest.advice;
+import jakarta.servlet.http.HttpServletRequest;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ProblemDetail;
@@ -27,11 +28,13 @@
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
+import java.net.URI;
+import java.time.LocalDateTime;
+
/**
* Global Exception handler for REST controllers.
*
- * This class handles exceptions thrown by REST controllers and returns
- * appropriate HTTP responses to the client.
+ * This class handles exceptions thrown by REST controllers and returns appropriate HTTP responses to the client.
*
* @author Vitaliy Fedoriv
* @author Alexander Dudkin
@@ -40,63 +43,69 @@
public class ExceptionControllerAdvice {
/**
- * Private method for constructing the {@link ProblemDetail} object passing the name and details of the exception class.
+ * Private method for constructing the {@link ProblemDetail} object passing the name and details of the exception
+ * class.
*
- * @param ex Object referring to the thrown exception.
+ * @param ex Object referring to the thrown exception.
* @param status HTTP response status.
+ * @param url URL request.
*/
- private ProblemDetail detailBuild(Exception ex, HttpStatus status) {
+ private ProblemDetail detailBuild(Exception ex, HttpStatus status, StringBuffer url) {
ProblemDetail detail = ProblemDetail.forStatus(status);
- detail.setTitle(ex.getClass().getName());
+ detail.setType(URI.create(url.toString()));
+ detail.setTitle(ex.getClass().getSimpleName());
detail.setDetail(ex.getLocalizedMessage());
+ detail.setProperty("timestamp", LocalDateTime.now());
return detail;
}
/**
* Handles all general exceptions by returning a 500 Internal Server Error status with error details.
*
- * @param e The {@link Exception} to be handled
+ * @param e The {@link Exception} to be handled
+ * @param request {@link HttpServletRequest} object referring to the current request.
* @return A {@link ResponseEntity} containing the error information and a 500 Internal Server Error status
*/
@ExceptionHandler(Exception.class)
@ResponseBody
- public ResponseEntity handleGeneralException(Exception e) {
+ public ResponseEntity handleGeneralException(Exception e, HttpServletRequest request) {
HttpStatus status = HttpStatus.INTERNAL_SERVER_ERROR;
- ProblemDetail detail = this.detailBuild(e, status);
+ ProblemDetail detail = this.detailBuild(e, status, request.getRequestURL());
return ResponseEntity.status(status).body(detail);
}
/**
- * Handles {@link DataIntegrityViolationException} which typically indicates database constraint violations.
- * This method returns a 404 Not Found status if an entity does not exist.
+ * 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
+ * @param request {@link HttpServletRequest} object referring to the current request.
* @return A {@link ResponseEntity} containing the error information and a 404 Not Found status
*/
@ExceptionHandler(DataIntegrityViolationException.class)
@ResponseBody
- public ResponseEntity handleDataIntegrityViolationException(DataIntegrityViolationException ex) {
+ public ResponseEntity handleDataIntegrityViolationException(DataIntegrityViolationException ex, HttpServletRequest request) {
HttpStatus status = HttpStatus.NOT_FOUND;
- ProblemDetail detail = this.detailBuild(ex, status);
+ ProblemDetail detail = this.detailBuild(ex, status, request.getRequestURL());
return ResponseEntity.status(status).body(detail);
}
/**
* Handles exception thrown by Bean Validation on controller methods parameters
*
- * @param ex The {@link MethodArgumentNotValidException} to be handled
- *
+ * @param ex The {@link MethodArgumentNotValidException} to be handled
+ * @param request {@link HttpServletRequest} object referring to the current request.
* @return A {@link ResponseEntity} containing the error information and a 400 Bad Request status.
*/
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseBody
- public ResponseEntity handleMethodArgumentNotValidException(MethodArgumentNotValidException ex) {
+ public ResponseEntity handleMethodArgumentNotValidException(MethodArgumentNotValidException ex, HttpServletRequest request) {
HttpStatus status = HttpStatus.BAD_REQUEST;
BindingErrorsResponse errors = new BindingErrorsResponse();
BindingResult bindingResult = ex.getBindingResult();
if (bindingResult.hasErrors()) {
errors.addAllErrors(bindingResult);
- ProblemDetail detail = this.detailBuild(ex, status);
+ ProblemDetail detail = this.detailBuild(ex, status, request.getRequestURL());
return ResponseEntity.status(status).body(detail);
}
return ResponseEntity.status(status).build();
diff --git a/src/main/resources/openapi.yml b/src/main/resources/openapi.yml
index 792cfa07..f48443ca 100755
--- a/src/main/resources/openapi.yml
+++ b/src/main/resources/openapi.yml
@@ -57,7 +57,7 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
/owners:
post:
tags:
@@ -84,13 +84,13 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
500:
description: Server error.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
get:
tags:
- owner
@@ -131,7 +131,7 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
/owners/{ownerId}:
get:
tags:
@@ -173,19 +173,19 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
404:
description: Owner not found.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
500:
description: Server error.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
put:
tags:
- owner
@@ -221,19 +221,19 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
404:
description: Owner not found.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
500:
description: Server error.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
delete:
tags:
@@ -275,19 +275,19 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
404:
description: Owner not found.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
500:
description: Server error.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
/owners/{ownerId}/pets:
post:
tags:
@@ -324,19 +324,19 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
404:
description: Pet or Owner not found.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
500:
description: Server error.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
/owners/{ownerId}/pets/{petId}:
get:
tags:
@@ -387,19 +387,19 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
404:
description: Owner or pet not found.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
500:
description: Server error.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
put:
tags:
- pet
@@ -441,19 +441,19 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
404:
description: Pet not found for this owner.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
500:
description: Server error.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
/owners/{ownerId}/pets/{petId}/visits:
post:
tags:
@@ -499,19 +499,19 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
404:
description: Pet not found for this owner.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
500:
description: Server error.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
/pettypes:
get:
tags:
@@ -545,7 +545,7 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
post:
tags:
- pettypes
@@ -583,19 +583,19 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
404:
description: Pet Type not found.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
500:
description: Server error.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
/pettypes/{petTypeId}:
get:
tags:
@@ -637,19 +637,19 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
404:
description: Pet Type not found.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
500:
description: Server error.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
put:
tags:
- pettypes
@@ -697,19 +697,19 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
404:
description: Pet Type not found.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
500:
description: Server error.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
delete:
tags:
- pettypes
@@ -750,19 +750,19 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
404:
description: Pet type not found.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
500:
description: Server error.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
/pets:
get:
@@ -797,7 +797,7 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
post:
tags:
- pet
@@ -835,19 +835,19 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
404:
description: Pet not found.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
500:
description: Server error.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
/pets/{petId}:
get:
tags:
@@ -889,19 +889,19 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
404:
description: Pet not found.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
500:
description: Server error.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
put:
tags:
- pet
@@ -949,19 +949,19 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
404:
description: Pet not found.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
500:
description: Server error.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
delete:
tags:
- pet
@@ -1002,19 +1002,19 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
404:
description: Pet not found.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
500:
description: Server error.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
/visits:
get:
tags:
@@ -1048,7 +1048,7 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
post:
tags:
- visit
@@ -1086,19 +1086,19 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
404:
description: Visit not found.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
500:
description: Server error.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
/visits/{visitId}:
get:
tags:
@@ -1140,19 +1140,19 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
404:
description: Visit not found.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
500:
description: Server error.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
put:
tags:
- visit
@@ -1200,19 +1200,19 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
404:
description: Visit not found.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
500:
description: Server error.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
delete:
tags:
- visit
@@ -1253,19 +1253,19 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
404:
description: Visit not found.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
500:
description: Server error.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
/specialties:
get:
tags:
@@ -1299,7 +1299,7 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
post:
tags:
- specialty
@@ -1337,19 +1337,19 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
404:
description: Specialty not found.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
500:
description: Server error.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
/specialties/{specialtyId}:
get:
tags:
@@ -1391,19 +1391,19 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
404:
description: Specialty not found.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
500:
description: Server error.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
put:
tags:
- specialty
@@ -1451,19 +1451,19 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
404:
description: Specialty not found.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
500:
description: Server error.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
delete:
tags:
- specialty
@@ -1504,19 +1504,19 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
404:
description: Specialty not found.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
500:
description: Server error.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
/vets:
get:
tags:
@@ -1550,7 +1550,7 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
post:
tags:
@@ -1589,19 +1589,19 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
404:
description: Vet not found.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
500:
description: Server error.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
/vets/{vetId}:
get:
tags:
@@ -1643,19 +1643,19 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
404:
description: Vet not found.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
500:
description: Server error.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
put:
tags:
- vet
@@ -1703,19 +1703,19 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
404:
description: Vet not found.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
500:
description: Server error.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
delete:
tags:
- vet
@@ -1756,19 +1756,19 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
404:
description: Vet not found.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
500:
description: Server error.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
/users:
post:
tags:
@@ -1807,58 +1807,57 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
404:
description: User not found.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
500:
description: Server error.
content:
application/json:
schema:
- $ref: '#/components/schemas/RestError'
+ $ref: '#/components/schemas/ProblemDetail'
components:
schemas:
- RestError:
- title: REST Error
+ ProblemDetail:
+ title: Problem Detail
description: The schema for all error responses.
type: object
properties:
+ type:
+ title: Type
+ description: Full URL that originated the error response.
+ type: string
+ format: text
+ example: 'http://localhost:9966/petclinic/api/owner'
+ readOnly: true
+ title:
+ title: Title
+ description: The short error title.
+ type: string
+ example: NoResourceFoundException
+ readOnly: true
status:
title: Status
- description: The HTTP status code.
+ description: HTTP status code
type: integer
- format: int32
- example: 400
- readOnly: true
- error:
- title: Error
- description: The short error message.
- type: string
- example: Bad Request
+ example: 500
readOnly: true
- path:
- title: Path
- description: The path of the URL for this request.
+ detail:
+ title: Detail
+ description: The long error message.
type: string
- format: uri
- example: '/api/owners'
+ example: 'No static resource api/owner.'
readOnly: true
timestamp:
title: Timestamp
description: The time the error occurred.
type: string
format: date-time
- example: '2019-08-21T21:41:46.158+0000'
- readOnly: true
- message:
- title: Message
- description: The long error message.
- type: string
- example: 'Request failed schema validation'
+ example: '2024-11-23T13:59:21.3820407'
readOnly: true
schemaValidationErrors:
title: Schema validation errors
@@ -1866,18 +1865,12 @@ components:
type: array
items:
$ref: '#/components/schemas/ValidationMessage'
- trace:
- title: Trace
- description: The stacktrace for this error.
- type: string
- example: 'com.atlassian.oai.validator.springmvc.InvalidRequestException: ...'
- readOnly: true
required:
+ - type
+ - title
- status
- - error
- - path
+ - detail
- timestamp
- - message
- schemaValidationErrors
ValidationMessage:
title: Validation message