package com.example.demo.exception;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ErrorResponse> handleResourceNotFound(
ResourceNotFoundException ex,
WebRequest request
) {
ErrorResponse error = new ErrorResponse(
HttpStatus.NOT_FOUND.value(),
ex.getMessage(),
request.getDescription(false),
LocalDateTime.now()
);
return new ResponseEntity<>(error, HttpStatus.NOT_FOUND);
}
@ExceptionHandler(BadRequestException.class)
public ResponseEntity<ErrorResponse> handleBadRequest(
BadRequestException ex,
WebRequest request
) {
ErrorResponse error = new ErrorResponse(
HttpStatus.BAD_REQUEST.value(),
ex.getMessage(),
request.getDescription(false),
LocalDateTime.now()
);
return new ResponseEntity<>(error, HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ValidationErrorResponse> handleValidationErrors(
MethodArgumentNotValidException ex
) {
Map<String, String> errors = new HashMap<>();
ex.getBindingResult().getAllErrors().forEach((error) -> {
String fieldName = ((FieldError) error).getField();
String errorMessage = error.getDefaultMessage();
errors.put(fieldName, errorMessage);
});
ValidationErrorResponse response = new ValidationErrorResponse(
HttpStatus.BAD_REQUEST.value(),
"Validation failed",
errors,
LocalDateTime.now()
);
return new ResponseEntity<>(response, HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(DuplicateResourceException.class)
public ResponseEntity<ErrorResponse> handleDuplicateResource(
DuplicateResourceException ex,
WebRequest request
) {
ErrorResponse error = new ErrorResponse(
HttpStatus.CONFLICT.value(),
ex.getMessage(),
request.getDescription(false),
LocalDateTime.now()
);
return new ResponseEntity<>(error, HttpStatus.CONFLICT);
}
@ExceptionHandler(UnauthorizedException.class)
public ResponseEntity<ErrorResponse> handleUnauthorized(
UnauthorizedException ex,
WebRequest request
) {
ErrorResponse error = new ErrorResponse(
HttpStatus.UNAUTHORIZED.value(),
ex.getMessage(),
request.getDescription(false),
LocalDateTime.now()
);
return new ResponseEntity<>(error, HttpStatus.UNAUTHORIZED);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResponse> handleGlobalException(
Exception ex,
WebRequest request
) {
ErrorResponse error = new ErrorResponse(
HttpStatus.INTERNAL_SERVER_ERROR.value(),
"An unexpected error occurred",
request.getDescription(false),
LocalDateTime.now()
);
// Log the full exception for debugging
ex.printStackTrace();
return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
package com.example.demo.exception;
import java.time.LocalDateTime;
import java.util.Map;
public class ErrorResponse {
private int status;
private String message;
private String path;
private LocalDateTime timestamp;
public ErrorResponse(int status, String message, String path, LocalDateTime timestamp) {
this.status = status;
this.message = message;
this.path = path;
this.timestamp = timestamp;
}
// Getters and setters
public int getStatus() { return status; }
public void setStatus(int status) { this.status = status; }
public String getMessage() { return message; }
public void setMessage(String message) { this.message = message; }
public String getPath() { return path; }
public void setPath(String path) { this.path = path; }
public LocalDateTime getTimestamp() { return timestamp; }
public void setTimestamp(LocalDateTime timestamp) { this.timestamp = timestamp; }
}
class ValidationErrorResponse extends ErrorResponse {
private Map<String, String> errors;
public ValidationErrorResponse(
int status,
String message,
Map<String, String> errors,
LocalDateTime timestamp
) {
super(status, message, "", timestamp);
this.errors = errors;
}
public Map<String, String> getErrors() { return errors; }
public void setErrors(Map<String, String> errors) { this.errors = errors; }
}
package com.example.demo.exception;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ResponseStatus;
@ResponseStatus(HttpStatus.NOT_FOUND)
public class ResourceNotFoundException extends RuntimeException {
public ResourceNotFoundException(String message) {
super(message);
}
public ResourceNotFoundException(String resourceName, String fieldName, Object fieldValue) {
super(String.format("%s not found with %s: '%s'", resourceName, fieldName, fieldValue));
}
}
@ResponseStatus(HttpStatus.BAD_REQUEST)
class BadRequestException extends RuntimeException {
public BadRequestException(String message) {
super(message);
}
}
@ResponseStatus(HttpStatus.CONFLICT)
class DuplicateResourceException extends RuntimeException {
public DuplicateResourceException(String message) {
super(message);
}
}
@ResponseStatus(HttpStatus.UNAUTHORIZED)
class UnauthorizedException extends RuntimeException {
public UnauthorizedException(String message) {
super(message);
}
}