Foundation · Build

@RestController vs @Controller

@Controller returns view names unless @ResponseBody opts a method into message conversion; @RestController bakes that opt-in in for the whole class.

Primary source: Spring MVC: @RestController & @ResponseBody

15 min

Lesson 3 of 11

1d streak

The Architectural Question

Returning a DTO from @Controller without @ResponseBody sends Spring hunting for a view template named after your object instead of writing JSON to the socket.

What this guide proves

  • @RestController
  • @RequestMapping
  • MessageConverters

Legacy XML MVC Configuration vs Modern Annotations

Before Spring Boot auto-configuration and the @RestController annotation, configuring Spring MVC required extensive XML. You had to explicitly declare the DispatcherServlet in web.xml and map handler components in a separate Spring XML context.

WEB-INF/dispatcher-servlet.xml
<!-- Legacy XML approach to Spring MVC -->
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="...">

    <!-- 1. Enable MVC annotation driven features -->
    <mvc:annotation-driven/>

    <!-- 2. Scan for @Controller components -->
    <context:component-scan base-package="com.example.controllers"/>
</beans>

Architectural Boundary · Do Not Confuse

Concept A

XML <mvc:annotation-driven/>

Concept B

@RestController and Spring Boot

In the past, you explicitly wired MVC components. Today, Spring Boot detects Tomcat and automatically registers DispatcherServlet and Jackson message converters without a single line of XML.

@RestController vs @Controller: View resolution vs message conversion

The difference between @Controller and @RestController is not cosmetic; it alters how Spring MVC handles method return values.

Architectural Boundary · Do Not Confuse

Concept A

@Controller (HTML Template Mode)

Concept B

@RestController (REST API Mode)

@Controller expects return values to be view template names (e.g. "index" -> index.html via Thymeleaf). @RestController is meta-annotated with @ResponseBody, instructing Spring to serialize the return object directly into JSON/XML via HttpMessageConverters without view resolution.

AnnotationMeta-AnnotationsReturn Value InterpretationTypical Use Case
@Controller@ComponentString = View template name; Model passed to template engineServer-rendered web pages (Thymeleaf, FreeMarker, JSP)
@RestController@Controller + @ResponseBodyObject serialized into response body via JacksonREST APIs, JSON/XML web services, Mobile/SPA backends
ApiController.java
@RestController // Combines @Controller + @ResponseBody
@RequestMapping("/api/v1/tasks")
public class TaskApiController {
    @GetMapping("/{id}")
    public TaskDto getTask(@PathVariable Long id) {
        return new TaskDto(id, "Read the Web module"); // Serialized to JSON automatically!
    }
}

The HttpMessageConverter serialization pipeline

When a method in a @RestController returns an object, Spring's RequestResponseBodyMethodProcessor iterates through the registered HttpMessageConverter list to find a converter matching the requested Accept header and return type:

  1. 01ByteArrayHttpMessageConverter: Handles byte[] payloads.
  2. 02StringHttpMessageConverter: Handles raw text/plain strings.
  3. 03ResourceHttpMessageConverter: Handles file downloads and streamable resources.
  4. 04MappingJackson2HttpMessageConverter: Handles JSON serialization via Jackson ObjectMapper.

Break it deliberately: Circular view resolution error on @Controller

Returning a String from a class annotated with @Controller (instead of @RestController) tricks Spring MVC into treating the string as a template file name.

TemplateConfusionController.java
@Controller // Mistake: intended to return REST data!
@RequestMapping("/api/status")
public class StatusController {

    @GetMapping
    public String getStatus() {
        return "UP"; // Spring searches for a template named "UP.html"!
    }
}
Terminal / Diagnostic Output
HTTP/1.1 500 Internal Server Error
org.springframework.web.servlet.DispatcherServlet - Error resolving template [UP], template might not exist or might not be accessible
jakarta.servlet.ServletException: Circular view path [UP]: would dispatch back to the current handler URL [/api/status] again.

The Fix

Change @Controller to @RestController, or add @ResponseBody to the method to opt into message conversion.

Check your understanding

Active Recall Checkpoint

What composed annotation combines @Controller with class-level @ResponseBody?

Hint: Think about response payload writing.

Show answer & explanation

@RestController is the composed annotation: it combines @Controller and class-level @ResponseBody. Adding @ResponseBody to a method opts that method into message conversion without changing the class annotation.

Active Recall Checkpoint

Why does returning a String from a @Controller without @ResponseBody cause a circular view path exception?

Hint: What does the ViewResolver do with the string?

Show answer & explanation

Spring treats the returned string as a view template name. If no template engine handles it, Spring forwards to that path as a servlet resource, resulting in circular dispatch back to the handler.

Synthesis & Production Verification

Production Acceptance Criteria

  • Explain what @ResponseBody changes about return-value handling
  • Convert a view-returning controller into a data controller
  • Map GET and POST routes with @GetMapping and @PostMapping

Architectural & Technical Review

Core Interview Questions

Q01What is the architectural distinction between @Controller and @RestController?Show answer

@Controller returns view names resolved by ViewResolvers to render HTML templates. @RestController has @ResponseBody meta-annotated, writing serialized JSON/XML bytes directly to the HTTP socket.

Q02Which component coordinates return value serialization in Spring MVC?Show answer

RequestResponseBodyMethodProcessor inspects the Accept header and return type, selecting an HttpMessageConverter (like Jackson) to write the response payload.

Q03Why does removing @ResponseBody from a DTO endpoint produce a circular view error?Show answer

Spring attempts to resolve the endpoint URI as an internal view template name, resulting in a recursive forward loop back to the same path.

Production Pitfalls

Critical Anti-Patterns

  • Pitfall: Mixing view templates with JSON APIs in one controller — Combine @ResponseBody with standard view resolution only when strictly necessary; prefer dedicated @RestController classes for APIs.
  • Pitfall: Returning raw collections without encapsulation — Returning top-level JSON arrays limits future response metadata additions; prefer container objects or records.

Primary Documentation & Specifications

Supplementary Module Resources