A second batch of 16 MVC misses, and the failure pattern in them is the opposite of the one on your exam papers. On the real papers you over-select — ticking two or three options where one is right. Here, 7 of the 16 were under-selection: you ticked only correct options and still lost the mark because you stopped too early. On one question all four options were correct. Same instinct, opposite direction — and both are fixed by the same habit.
Seven of these sixteen were under-selection — every option you ticked was correct, and you still scored zero because at least one correct option went unticked. Look at how generous these questions actually were:
| Question | Correct options | Only wrong option |
|---|---|---|
| Q30 · view technologies | 4 of 4 | none — everything was true |
| Q15 · auto-provided arguments | 4 of 4 | none — everything was true |
| Q12 · RestTemplate headers | 4 of 5 | "getForEntity accepts an HttpEntity" |
| Q14 · controller method arguments | 4 of 5 | ModelAndView (a return type) |
| Q44 · message converters | 3 of 4 | SOAP |
| Q26 · request workflow | 2 of 4 | the two swapping HandlerMapping/HandlerAdapter |
| Q27 · RestTemplate methods | 2 of 4 | two false claims about return types |
Two of them had no wrong answer at all. On Q30 and Q15 the correct response was to tick everything — and "everything is true" has now appeared six times across your papers and banks. It is a real and repeated pattern, not a trick.
The fix is one habit, and it cures both directions. A multi-select is not one question — it is N independent true/false questions. Rule each option true or false on its own merits, then tick every true one. Do that and you cannot over-select (you'd have to call a false statement true) or under-select (you'd have to leave a true one unticked). On your exam papers that habit is worth ~9 marks; here it is worth 7.
Four of these sixteen turn on this one distinction, and it is the same thing that cost you marks in attempts #4, #8 and #9. Learn it as two lists, not one.
| Type | Parameter? | Return? |
|---|---|---|
HttpServletRequest / ServletRequest | yes | NO |
HttpServletResponse / ServletResponse | yes | NO |
HttpSession | yes | no |
Principal | yes | no |
Locale, TimeZone | yes | no |
Errors / BindingResult | yes | no |
@PathVariable, @RequestParam, @RequestBody, @RequestHeader, @ModelAttribute | yes | no |
Model / ModelMap / Map | yes | yes |
ModelAndView | NO | yes |
String (view name), View, void | no | yes |
ResponseEntity, HttpEntity, HttpHeaders | no | yes |
The two traps, in both directions:
servlet objects go IN only (missed in #4, #8 and the round-1 bank), and
ModelAndView comes OUT only (missed here in Q14). Model is the one type that
legitimately does both — as a parameter you populate it, as a return value it is the model.
request
│
▼
┌──────────────────┐
│ DispatcherServlet │ the FRONT CONTROLLER — orchestrates, never does the work itself
└──────────────────┘
│ 1. WHICH handler? ──► HandlerMapping (finds — does not invoke)
│ 2. INVOKE it ──► HandlerAdapter (invokes — does not find)
│ 3. name → View ──► ViewResolver (a CHAIN, tried in order)
│ 4. render ──► View
▼
response
DispatcherServlet@Controller
handles specific requests; the question asks for the central piece.
@WebServlet is Jakarta EE, not Spring at all.The word doing the work in the stem is "central". A controller is a leaf; the
DispatcherServlet is the hub every request passes through. It also owns exception handling
(via HandlerExceptionResolver), which no individual controller does.
HandlerMapping finds; HandlerAdapter invokes| Statement | Verdict |
|---|---|
| DispatcherServlet uses both HandlerMapping and HandlerAdapter | TRUE |
| DispatcherServlet is the front controller | TRUE |
| "HandlerAdapter defines a strategy for mapping requests" | false — that's HandlerMapping |
| "HandlerMapping handles requests by invoking the method" | false — that's HandlerAdapter |
Read the verb, not the noun. Both false options name a real component and pair it
with the other one's verb. Mapping ⇒ HandlerMapping. Adapting/invoking ⇒
HandlerAdapter. The names literally say what they do.
Why two components rather than one: HandlerAdapter exists so the
DispatcherServlet can invoke different kinds of handler uniformly — an
@RequestMapping method, an old Controller interface implementation, an
HttpRequestHandler. Finding and invoking are genuinely separate concerns.
ViewResolversThe contract is designed for chaining. Each resolver returns null when it can't handle
a name, and the DispatcherServlet tries the next:
public interface ViewResolver {
View resolveViewName(String viewName, Locale locale) throws Exception;
// null ⇒ "not mine, try the next resolver"
}
| Statement | Verdict |
|---|---|
Multiple resolvers, priority controlled by Ordered/setOrder | TRUE |
They map a String view name to a View | TRUE |
| Spring ships implementations; registering one isn't obligatory | TRUE — DispatcherServlet.properties supplies a default |
| "Only one implementation allowed" | false |
Lower order value = higher priority. A typical chain is
ContentNegotiatingViewResolver → ThymeleafViewResolver →
InternalResourceViewResolver, with InternalResourceViewResolver last because it
never returns null — it always forwards, so nothing after it would ever run.
Both under-selected, and both answered by the master table above.
ModelAndView is the odd one out because it's a return type@PathVariable,
Principal, ServletRequest and HttpSession are all valid
parameters.Everything Spring can inject goes through a HandlerMethodArgumentResolver. The list is
long and generous — when a question asks "which may be arguments", the answer is usually "most of them":
@PostMapping("/orders/{id}")
public String handle(@PathVariable Long id, // URI template
@RequestParam String mode, // query string
@RequestBody OrderDto dto, // body
@RequestHeader("X-Trace") String trace,
Principal principal, // authenticated user
HttpSession session, // session
HttpServletRequest request, // raw request
Locale locale, // request locale
Model model) { … } // model to populate
ModelAndView is the exception, and it's a clean rule: it bundles the
model and the chosen view — a decision the handler makes, so it can only be produced, never
supplied. Spring has nothing to put in it before your method runs.
ModelAndView is an OUTPUT — it carries a decision only your method can make.Errors, Model, ServletRequest, ServletResponseThe one worth learning properly is Errors/BindingResult, because it has a
positional rule the exam likes:
@PostMapping("/users")
public String create(@Valid @ModelAttribute UserForm form,
BindingResult errors, // ← MUST come immediately after
Model model) {
if (errors.hasErrors()) return "form";
…
}
Errors/BindingResult must be declared directly after the validated
argument. Put anything between them and Spring can't associate the two — validation failures then throw
MethodArgumentNotValidException (a 400) instead of populating the object you're holding. That's not a
style rule; it's how the resolver pairs them.
ServletRequest/ServletResponse being valid is the mirror of the trap you
keep meeting: valid as parameters, never as return types.
@RequestMapping with no method attributeThis is the third time this fact has appeared across your papers and banks, so it's worth over-learning:
| Declaration | Handles |
|---|---|
@RequestMapping("/endpoint") | GET, POST, PUT, DELETE, PATCH — all of them |
@RequestMapping(value="/endpoint", method=GET) | GET only |
@GetMapping("/endpoint") | GET only — identical to the line above |
This is precisely why the shortcuts exist. A bare
@RequestMapping quietly exposes your GET handler to POST and DELETE too — so
@GetMapping is a security improvement as much as a readability one.
Note the general technique lesson in the distractor: "an exception will be thrown" on unremarkable code is nearly always wrong. The exam shows you broken code only when it says so.
method ⇒ every verb. That's why @GetMapping exists.statusCode attribute on @RequestMappingResponseEntity and @ResponseStatus on a
method — the two most standard ways there are. The question asked which is
not valid.The three genuine mechanisms:
| Mechanism | Where | Use for |
|---|---|---|
ResponseEntity.status(…).body(…) | return value | status decided at runtime |
@ResponseStatus(HttpStatus.CREATED) | a handler method | a fixed status for that endpoint |
@ResponseStatus(...) | a class — controller or exception | a default for all its methods / an error mapping |
@GetMapping(statusCode = …) | — | does not exist |
Why no statusCode attribute: mapping annotations describe
which requests reach this method — path, verb, headers, content types. The response is a different
concern, so it lives in a different annotation. Recognising that separation makes the invented attribute obvious.
And the polarity habit, since this is your fourth "which is NOT" slip across the papers: circle the negative word before reading the options, then say "I am looking for the wrong one" before you tick anything.
ResponseEntity or @ResponseStatus. Mapping annotations describe the REQUEST, never the response.@PathVariable does@RequestHeader and
@RequestMapping. Every option described a real annotation — you had to match
description to name.| Description | Annotation |
|---|---|
| Binds parts of a URI marked with template variables | @PathVariable — /users/{id} |
| Binds a web request parameter | @RequestParam — ?name=John |
| Binds a request header | @RequestHeader |
| Maps web requests onto handler methods | @RequestMapping |
Match on the noun in the description — "URI template" / "parameter" / "header" / "maps". Each description contains the word that names its annotation, so the pairing is mechanical once you look for it.
@RequestMapping is a convenience, not a
requirement.| Statement | Verdict |
|---|---|
@Controller is a stereotype annotation | TRUE — a specialisation of @Component |
| Annotated controllers have no direct Servlet/Portlet dependency | TRUE |
| No specific superclass or interface is required | TRUE |
| "All paths must share a prefix" | false — the class-level mapping is optional |
The historical point behind the two middle statements is worth having: Spring MVC
used to require inheritance — you extended AbstractController or implemented the
Controller interface, and your class was coupled to the Servlet API. Annotation-driven controllers
(Spring 2.5+) removed that entirely, which is what "non-invasive" means in practice: a POJO with
annotations.
Both under-selected — and headers on a RestTemplate call have now appeared in three separate
banks and papers.
getForEntity accepts an HttpEntity"HttpEntity and then passes it to getForEntity, which ignores
it.Why that call silently does the wrong thing — this is the genuinely interesting bit:
restTemplate.getForEntity(url, String.class, requestEntity);
// ^^^^^^^^^^^^^
// getForEntity(String url, Class<T> type, Object... uriVariables)
// the varargs are URI TEMPLATE VARIABLES — the entity is treated as a
// value for {0} in the URL, and the headers are never sent.
It compiles, it runs, and the Authorization header simply isn't there. That's what
makes it a good exam question and a nasty real-world bug.
| Method | Takes an HttpEntity? |
|---|---|
getForObject / getForEntity | no — trailing args are URI variables |
postForObject / postForEntity | yes, as the body argument |
exchange | yes — any verb, headers and body |
exchange(). On getFor*, trailing arguments are URI variables, not entities — the headers vanish silently.RestTemplate method return types under-selectedpostForObject hides the status · put and delete return voidgetForEntity returns a ResponseEntity, not a bare entity, and
getForObject takes a Class, not an ObjectFactory.The naming convention makes the whole API predictable:
| Suffix | Returns | Status visible? |
|---|---|---|
…ForObject | the deserialised body | no |
…ForEntity | ResponseEntity<T> — body + status + headers | yes |
put, delete | void | no |
exchange | ResponseEntity<T> | yes |
Read the suffix and you know the answer: Object = just the body,
Entity = the whole response. So "with postForObject it is impossible to check the status
code" is true by construction — there's nowhere for it to appear.
Note also that RestTemplate throws on 4xx/5xx by default
(HttpClientErrorException / HttpServerErrorException), so "checking the status" mostly
means distinguishing among the 2xx codes.
ViewResolver for every one of them.| Technology | Resolver |
|---|---|
| JSP | InternalResourceViewResolver |
| Thymeleaf | ThymeleafViewResolver — Boot's default |
| FreeMarker | FreeMarkerViewResolver |
| Groovy Markup | GroovyMarkupViewResolver |
| XSLT | XsltViewResolver |
| Tiles | TilesViewResolver |
| JSON / XML | MappingJackson2JsonView, MarshallingView |
The instinct to correct: "supported by Spring" is much broader than "the Boot default". Thymeleaf is the default; JSP, XSLT and Tiles are older but genuinely supported. Only reject a view technology if it isn't one — which is how JSON slipped past you on a paper question.
HttpMessageConverters under-selected| Converter | Handles | Media type |
|---|---|---|
ByteArrayHttpMessageConverter | byte[] | application/octet-stream |
StringHttpMessageConverter | String | text/plain |
FormHttpMessageConverter | form data | application/x-www-form-urlencoded |
Jaxb2RootElementHttpMessageConverter | JAXB2-annotated objects | application/xml |
MappingJackson2HttpMessageConverter | JSON (if Jackson is present) | application/json |
Why SOAP is excluded is a real architectural point: message converters map a body to an object. SOAP isn't a body format — it's a full protocol with an envelope, headers, a WSDL contract and its own addressing. It can't be handled by a body converter, which is why it lives in a separate project, Spring-WS.
Converters are tried in order and the first supporting the negotiated media type wins — the same
chain-of-responsibility shape as the ViewResolver chain.
ContentNegotiatingViewResolver, HttpMessageConverters — no "testing pages"What WebMvcAutoConfiguration actually gives you:
| Feature | Detail |
|---|---|
| Static resources | served from /static, /public, /resources, /META-INF/resources |
ContentNegotiatingViewResolver | picks a view by the Accept header |
HttpMessageConverters | Jackson for JSON, plus the defaults above |
| Error handling | BasicErrorController — Whitelabel page + JSON |
| Favicon, welcome page | index.html from a static location |
Converter/Formatter beans | auto-registered |
| does not exist |
The idea the distractor exploits is real but comes from elsewhere: an interactive UI for your endpoints is Swagger/OpenAPI (springdoc-openapi), a third-party library you add. Boot ships nothing like it.
PATCH — GET, PUT and DELETE all are| Method | Safe | Idempotent | Why |
|---|---|---|---|
GET, HEAD, OPTIONS | yes | yes | changes nothing at all |
PUT | no | yes | replaces — same body, same end state |
DELETE | no | yes | gone after one call, still gone after five |
PATCH | no | NO | partial change — may be relative ("add 5") |
POST | no | no | creates a new resource each time |
Idempotent means the end state is the same, not the response. That's the misunderstanding that makes DELETE look non-idempotent: the second call returns 404 rather than 204, but the resource is absent either way — and it's the state that defines idempotency.
Why PATCH isn't: PUT {"balance": 100} sets the balance to 100 however
many times you send it. PATCH {"op":"increment","by":5} adds 5 each time. PUT states a
destination; PATCH describes a change — and repeated changes accumulate.
And safe ≠ idempotent: safe means "no side effects at all" (only the read methods). Idempotent is the weaker property — "repeating it changes nothing further". Every safe method is idempotent; PUT and DELETE are idempotent without being safe.
MVC exists to give each part one reason to change:
| Component | Owns | Changes when… |
|---|---|---|
| Model | data and business logic | the business rules change |
| View | presentation | the UI changes |
| Controller | input handling and coordination | the interaction flow changes |
Swappability is a consequence, not the purpose — and a partial one. You can realistically swap the View (JSP → Thymeleaf) because rendering is genuinely pluggable. Swapping the Model or Controller means rewriting your application, since they hold the behaviour. The statement overclaims by treating all three as interchangeable parts.
Note the exam-technique signal: a statement containing "easily" or "each of them" is usually overclaiming. Absolutes and universals on conceptual questions are a reliable tell — the same shape as "@Required is for handling dependencies" or "an application can have only one ViewResolver".
@WebServlet is Jakarta EEnull means "pass"; you needn't register one; InternalResourceViewResolver goes lastModelAndView can only be RETURNEDErrors/BindingResult must sit immediately after the @Valid argument@RequestMapping handles every verb — the reason @GetMapping existsResponseEntity or @ResponseStatus (method, class, or exception). There is no statusCode attributegetForEntity's trailing args are URI variables — pass an HttpEntity and the headers vanish silentlyput/delete return void · exchange does everything