A Spring MVC request passes through the Servlet filter chain before DispatcherServlet selects a handler, resolves arguments and writes the response. A controller is only one stage of that path.
Spring MVC request lifecycle: from servlet filter to response body
Mark the rejection point
Security filters can reject a request before any controller runs. Inside MVC, handler mapping selects the controller method. Argument resolvers convert the path and body into Java values; validation can reject those values before the method is invoked. After the method returns, a message converter writes a representation that matches the negotiated media type.
package in.aitrove.receipts;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
record ReceiptView(long id, String state) {}
@RestController
@RequestMapping("/api/receipts")
class ReceiptReadController {
private final ReceiptReader receiptReader;
ReceiptReadController(ReceiptReader receiptReader) {
this.receiptReader = receiptReader;
}
@GetMapping("/{receiptId}")
ResponseEntity<ReceiptView> read(@PathVariable long receiptId) {
return receiptReader.find(receiptId)
.map(ResponseEntity::ok)
.orElseGet(() -> ResponseEntity.notFound().build());
}
}
interface ReceiptReader {
java.util.Optional<ReceiptView> find(long receiptId);
}A nonnumeric path segment fails conversion before read is entered. An unknown numeric ID reaches the reader and returns 404 here. A missing JSON converter or an unacceptable requested media type can fail at a different stage. Record those cases separately in an HTTP test.
Keep costs attached to the responsible layer
Routing and argument conversion are normally bounded by request size and configured mappings. The database lookup dominates this example once the request reaches the reader. Bound body size before deserialization; a small controller method does not make a huge incoming body cheap.
Common Mistakes
- Logging “controller failed” for a request rejected by a security filter.
- Returning null for absence and hoping serialization creates a 404.
- Assuming a unit test of read exercises routing, conversion or security.
Read next
Filters and interceptors, media type failures, and MockMvc boundaries.
