Skip to main content

Global Exception Handling in Spring Boot

Exception Handling in Spring Boot (Deep Dive)

Exception Handling is one of the most important topics in Spring Boot interviews because every real-world application faces errors. Think about these common scenarios:

  • User enters invalid data
  • Record not found in the database
  • Database connection fails
  • NullPointerException occurs
  • External API fails
  • Business rule violation occurs

Instead of showing ugly stack traces to users, we handle exceptions properly and return meaningful, structured responses.


1. What is Exception Handling?

Standard Definition

Exception Handling is a mechanism used to handle runtime errors gracefully without terminating the application.

Without Exception Handling

@GetMapping("/user/{id}") public User getUser(@PathVariable Long id) { User user = userRepository.findById(id).get(); return user; }

If the user does not exist, a NoSuchElementException occurs, and the user gets an ugly default response:

{ "timestamp": "...", "status": 500, "error": "Internal Server Error" }

With Exception Handling

We return something much more user-friendly:

{ "message": "User not found", "status": 404 }

Types of Exception Handling in Spring Boot

  • 1. Local Exception Handling: Uses @ExceptionHandler to handle exceptions inside a single controller.
  • 2. Global Exception Handling: Uses @ControllerAdvice or @RestControllerAdvice to handle exceptions across the entire application.
  • 3. Custom Exceptions: Standard classes extending RuntimeException used for business-specific errors (e.g., UserNotFoundException).

2. Local Exception Handling

Local Exception Handling manages exceptions only inside a specific controller. It is implemented using the @ExceptionHandler annotation.

Implementation Example

@RestController @RequestMapping("/users") public class UserController { @GetMapping("/{id}") public String getUser(@PathVariable Long id) { if(id == 0) { throw new RuntimeException("User Not Found"); } return "User Found"; } @ExceptionHandler(RuntimeException.class) public ResponseEntity<String> handleException(RuntimeException ex) { return ResponseEntity .status(HttpStatus.NOT_FOUND) .body(ex.getMessage()); } }

Internal Working

When an exception occurs (e.g., throw new RuntimeException()), Spring's DispatcherServlet checks if there is any @ExceptionHandler inside the current controller. If a match is found, it calls the matching handler method.

Note: Handling a superclass like RuntimeException will also automatically handle its subclasses, such as NullPointerException and IllegalArgumentException.


3. Global Exception Handling

The problem with Local Handling is code duplication. If you have UserController, ProductController, and OrderController, you would have to write @ExceptionHandler methods in every single one of them. The solution is Global Exception Handling.

What is @ControllerAdvice?

@ControllerAdvice is a centralized exception handling mechanism that acts as an interceptor to handle exceptions across ALL controllers in your application.

Global Handler Architecture

UserController \ ProductController -➔ @ControllerAdvice -➔ Common Error Response OrderController /

Example Implementation

@ControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(RuntimeException.class) public ResponseEntity<String> handleRuntimeException(RuntimeException ex) { return ResponseEntity .status(HttpStatus.BAD_REQUEST) .body(ex.getMessage()); } }

4. @RestControllerAdvice

This is a heavily requested interview topic. @RestControllerAdvice is simply a combination of @ControllerAdvice and @ResponseBody.

Feature @ControllerAdvice @RestControllerAdvice
Returns View Yes (JSP/HTML) No
Returns JSON/XML Requires explicit @ResponseBody Automatically
Primary Use Case Traditional MVC Apps REST APIs

5. Custom Exceptions

Real-world projects rarely throw a generic RuntimeException. Instead, they throw domain-specific exceptions like UserNotFoundException. This greatly improves readability, maintainability, and debugging.

Creating a Custom Exception

public class UserNotFoundException extends RuntimeException { public UserNotFoundException(String message) { super(message); } }

Production-Grade Error Response DTO

Instead of returning raw Strings, standard practice dictates returning a structured Data Transfer Object (DTO).

public class ErrorResponse { private String message; private int status; private LocalDateTime timestamp; // getters and setters }

Integrating with the Global Handler

@RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(UserNotFoundException.class) public ResponseEntity<ErrorResponse> handleUserNotFound(UserNotFoundException ex){ ErrorResponse response = new ErrorResponse(); response.setMessage(ex.getMessage()); response.setStatus(404); response.setTimestamp(LocalDateTime.now()); return new ResponseEntity<>(response, HttpStatus.NOT_FOUND); } }

6. Interview Summary Checklist

Top Interview Q&A

Q1: Difference between @ExceptionHandler and @ControllerAdvice?
A: @ExceptionHandler provides local exception handling restricted to a single controller. @ControllerAdvice provides global exception handling that intercepts errors across the entire application.

Q2: Why do Custom Exceptions extend RuntimeException?
A: Extending RuntimeException (an unchecked exception) reduces boilerplate code. It means you don't need to add throws UserNotFoundException to every method signature. The exception propagates automatically up to the global handler without forcing compiler checks.

Q3: Which layer should throw the Custom Exception?
A: Usually the Service Layer. The service layer contains the business logic and knows exactly when a business rule (like "User not found") is violated.

Q4: What is the Global Exception Handling Flow?
A: Client sends request → DispatcherServlet → Controller → Service → Exception occurs → Propagates upward → DispatcherServlet delegates to HandlerExceptionResolver → Spring searches for matching @ExceptionHandler in @RestControllerAdvice → Returns Error Response to client.

Standard Enterprise Project Structure

com.example │ ├── controller │ └── UserController.java ├── service │ └── UserService.java ├── repository │ └── UserRepository.java ├── exception │ ├── UserNotFoundException.java │ ├── ErrorResponse.java │ └── GlobalExceptionHandler.java └── entity └── User.java

Comments

Popular posts from this blog

How I Got Selected in MNC

Virtusa Sometimes success does not come from having the best coding skills or the perfect roadmap. Sometimes it comes from simply refusing to quit. This is the honest story of how I transitioned from a confused, rejected fresher to getting selected as an Associate Engineer at Virtusa. The Beginning: Confused About My Future After completing my graduation, I stared blankly at my career options. Like many freshers, I lacked a clear direction. Should I join a Java course? Should I prepare on my own? Should I just wait for campus placement opportunities? One day, I called my friend Chetan. He suggested I join Naresh i Technologies and start learning Java seriously. Still unsure of my path, I told him I needed time to think about it. A couple of days later, my phone buzzed with a WhatsApp message offering a job opportunity. They asked me to come for the next round of the recruitment process. Excitement completely took over. I packed my bags, traveled to th...

Spring Boot Introduction

Spring Boot Introduction: Architecture, Dependencies, and Embedded Servers Modern enterprise applications demand rapid development, frictionless deployment, and absolute minimal configuration. Before Spring Boot arrived, developers utilizing the Spring Framework wasted immense amounts of time configuring XML files, managing clashing dependencies, setting up clunky application servers, and stitching various Spring modules together manually. To eliminate these bottlenecks, Pivotal introduced Spring Boot . Built entirely on top of the traditional Spring Framework, Spring Boot is an "opinionated" framework. It aggressively simplifies application development by injecting auto-configuration, packaging starter dependencies, and embedding web servers directly into your application. This allows backend developers to focus entirely on building business logic rather than wrestling with infrastructure setup. What is Spring Boot? Spring Boot is a powerful extens...

Strings in C

C Programming: Working with Strings Unlike modern programming languages like Python or Java, C does not possess a dedicated "String" data type. Instead, C treats a string as a simple 1D array of characters. Real-life example: Think of a freight train. The train does not exist as one solid object; it consists of individual boxcars linked together. Similarly, a C string links individual characters side-by-side in memory. To let the computer know the train has ended, C attaches a special "caboose" called the Null Terminator ( \0 ). 1. Essential String Functions Handling strings manually requires complex loops. To save time, C provides a built-in library called <string.h> that contains powerful functions to manipulate text. strlen(): You use this to find the exact length of a string. The compiler counts the characters until it hits the \0 terminator. It does not count the terminator itself. strcpy(): You ...