What Is the Difference Between @ControllerAdvice and @RestControllerAdvice?

Published: (December 22, 2025 at 10:17 PM EST)
4 min read
Source: Dev.to

Source: Dev.to

realNameHidden

Learn the difference between @ControllerAdvice and @RestControllerAdvice in Spring Boot with clear explanations and end‑to‑end Java examples.

Introduction

Imagine you are building two applications using Spring Boot.

  • Traditional web application – shows HTML pages in the browser.
  • REST API – consumed by a mobile app or a frontend framework like React.

Now suppose something goes wrong—maybe a user is not found or an invalid request is sent.

Do you want to handle errors inside every controller? Of course not.

Spring provides a clean way to handle errors globally using @ControllerAdvice and @RestControllerAdvice.

Beginners often ask:

  • Are these two annotations the same?
  • When should I use which one?
  • Why do REST APIs behave differently?

In this blog we’ll explain the difference between @ControllerAdvice and @RestControllerAdvice using clear concepts and end‑to‑end working examples so you can confidently use them in real Spring Boot projects.

Core Concepts

What Is @ControllerAdvice?

@ControllerAdvice is used to handle exceptions globally across controllers. Think of it as a central error handler for your application.

Simple way to think about it
Instead of every controller handling errors on its own, a single manager handles them for everyone.

Key points

  • Works with @Controller (MVC applications)
  • Typically returns HTML views or ModelAndView
  • Requires @ResponseBody if you want JSON

Use cases

  • Web applications
  • Server‑side rendered pages (Thymeleaf, JSP)
  • Custom error pages

What Is @RestControllerAdvice?

@RestControllerAdvice is designed specifically for REST APIs. Technically, it is:

@ControllerAdvice + @ResponseBody

Simple way to think about it
Instead of returning an error page, it returns structured JSON data.

Key points

  • Works best with @RestController
  • Automatically converts responses to JSON
  • Ideal for microservices and APIs

Use cases

  • REST APIs
  • Mobile or frontend‑based applications
  • Microservices architecture

Key Difference at a Glance

Feature@ControllerAdvice@RestControllerAdvice
Application typeMVC / Web appsREST APIs
Default responseHTML / ViewJSON
Needs @ResponseBodyYesNo
Best suited forUI‑based appsAPIs & microservices

End‑to‑End Code Examples (Java 21)

Below are complete working examples showing how each annotation is used in a real scenario.

Example 1: End‑to‑End MVC Flow Using @ControllerAdvice

Step 1 – Custom Exception

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

Step 2 – MVC Controller

@Controller
@RequestMapping("/pages")
public class PageController {

    @GetMapping("/{id}")
    public String getPage(@PathVariable int id) {
        if (id != 1) {
            throw new PageNotFoundException("Page not found with id: " + id);
        }
        return "home"; // returns an HTML page
    }
}

Step 3 – Global Exception Handler Using @ControllerAdvice

@ControllerAdvice
public class GlobalMvcExceptionHandler {

    @ExceptionHandler(PageNotFoundException.class)
    public String handlePageNotFound(PageNotFoundException ex, Model model) {
        model.addAttribute("errorMessage", ex.getMessage());
        return "error"; // resolves to error.html
    }
}

Result: Browser receives an HTML error page – centralized error handling with clean controller code.

Example 2: End‑to‑End REST API Flow Using @RestControllerAdvice

Step 1 – Custom Exception

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

Step 2 – Error Response Model

import java.time.LocalDateTime;

public record ErrorResponse(
        int status,
        String message,
        LocalDateTime timestamp
) {}

Step 3 – REST Controller

@RestController
@RequestMapping("/users")
public class UserController {

    @GetMapping("/{id}")
    public String getUser(@PathVariable Long id) {
        if (!id.equals(1L)) {
            throw new ResourceNotFoundException("User not found with id: " + id);
        }
        return "User found";
    }
}

Step 4 – Global Exception Handler Using @RestControllerAdvice

@RestControllerAdvice
public class GlobalRestExceptionHandler {

    @ExceptionHandler(ResourceNotFoundException.class)
    public ResponseEntity handleResourceNotFound(
            ResourceNotFoundException ex) {

        ErrorResponse response = new ErrorResponse(
                HttpStatus.NOT_FOUND.value(),
                ex.getMessage(),
                LocalDateTime.now()
        );

        return ResponseEntity.status(HttpStatus.NOT_FOUND).body(response);
    }
}

Result (JSON response):

{
  "status": 404,
  "message": "User not found with id: 2",
  "timestamp": "2025-01-10T12:30:45"
}

Best Practices

  • Use @RestControllerAdvice for REST APIs – guarantees automatic serialization (e.g., JSON) and avoids missing @ResponseBody.
  • Use @ControllerAdvice for MVC apps only – ideal when you need to return views or templates.
  • Create consistent error‑response structures – helps frontend teams and API consumers handle errors uniformly.
  • Map correct HTTP status codes – use 400, 404, 401, 500, etc., appropriately for each error condition.
  • Avoid generic Exception handling first – always handle specific exceptions before falling back to Exception.class.

Common Mistakes to Avoid

  • ❌ Using @ControllerAdvice in REST APIs without @ResponseBody.
  • ❌ Returning HTML error pages from REST APIs.
  • ❌ Handling exceptions inside individual controllers instead of centralizing them.
  • ❌ Exposing stack traces or internal details in API responses.

Conclusion

The difference between @ControllerAdvice and @RestControllerAdvice lies in how your application communicates errors:

  • Use @ControllerAdvice for traditional web applications that return HTML.
  • Use @RestControllerAdvice for REST APIs that return JSON (or other body‑based formats).

Both annotations provide centralized, clean, and scalable exception handling. Understanding this distinction makes your Spring Boot applications easier to maintain and more professional—whether in real projects or during interviews.

Back to Blog

Related posts

Read more »