Spring MVC · Drill Round 3 · 9 misses · 23 drills

Spring MVC — Drill Round 3

Nine more MVC misses, and two of them are patterns you've now hit repeatedly. Q35 had all four options correct — the seventh "everything is true" question across your papers and banks. And Q38 asked which status codes indicate errors and you ticked 2xx and 3xx — success and redirection. That's the same inversion that cost you three marks on attempt #6. Neither is a knowledge gap.

5
Multiple wrong ticks
2
Under-selections
1
Inversion (Q38)
46
MVC misses, all rounds
Where this sits. Rounds 1, 2 and 3 now cover 46 Spring MVC misses and 80 drills — comfortably the most-covered topic on the site. MVC was 50% on your last paper and has never been above 75% in ten attempts. The material is now all here; what's left is repetition. Round 1 has the return-type and pipeline tables; round 2 has the arguments-in/values-out table and the under-selection finding; this round adds error handling, deployment and content negotiation.

Two repeat patterns, both free to fix

1 · "Everything is true" — now seven times. Q35 asked which annotations can go on controller method parameters. All four — @RequestParam, @RequestHeader, @ModelAttribute, @RequestBody — were correct, and you took fewer.

WhereQuestionCorrect options
Attempt #5Spring Data comparison keywords4 of 4
Attempt #9What spring.factories registers4 of 4
Attempt #10Spring mock objects (3 of 5)3 of 5
MVC round 2View technologies4 of 4
MVC round 2Auto-provided handler arguments4 of 4
Data clinicEmptyResultDataAccessException4 of 5
Here · Q35Parameter annotations4 of 4

"All of them" is a real answer and it recurs. When every option names something that plainly exists and does roughly what the stem describes, the answer is usually all of them. Rule each option true/false on its own merits and tick every true one — that habit alone is worth ~9 marks on your exam papers and 7 in round 2.

2 · The inversion, again. Q38 asked which status-code families indicate errors. You ticked 2xx (success) and 3xx (redirection) — the two that indicate no error at all. That is the same shape as attempt #6's three polarity slips (which log level is not valid → you ticked the valid ones; which can't render conditionally → you ticked the ones that can). Read the stem twice and name what you're hunting for before looking at the options.

Master table — the RestTemplate exception hierarchy

Q7 turns entirely on this, and it's the piece of RestTemplate you haven't met in rounds 1 or 2.

ExceptionThrown whenExample
HttpClientErrorException4xx — the client's fault404, 400, 403
HttpServerErrorException5xx — the server's fault500, 503
UnknownHttpStatusCodeExceptiona non-standard status codea custom 6xx
ResourceAccessExceptionno HTTP response at allconnection refused, timeout, DNS failure

All four extend RestClientException, and HttpClientErrorException/HttpServerErrorException share a parent HttpStatusCodeException — so catch (HttpStatusCodeException e) catches 4xx and 5xx together, which is often what you actually want.

The behaviour to remember: RestTemplate throws on 4xx and 5xx by default (via DefaultResponseErrorHandler). It does not hand you a ResponseEntity with a 404 in it — the exception fires first. Contrast TestRestTemplate, which is deliberately fault-tolerant and returns the response so you can assert on the status.

Jump to a section

① RestTemplate error handling — 1 ② Method parameters — 2 ③ Converters & content negotiation — 2 ④ WAR deployment & Servlet 3 — 2 ⑤ HTTP status categories — 1 ⑥ HATEOAS — 1

① RestTemplate error handling 1 miss

Q7 · Catching a 404 from getForEntity

Two true: the 404 returns the custom message, and HttpClientErrorException covers 4xx

Your answer: three wrong options ticked — "it retries automatically", "the body is always non-null", and "the catch block handles 5xx too". All three overstate what the code does.

Take the three false claims one at a time, because each is a useful fact in its own right:

ClaimWhy it's false
"getForEntity retries on network error"RestTemplate never retries. A connection failure throws ResourceAccessException immediately. Retrying needs Spring Retry or a resilience library
"ResponseEntity always has a non-null body"The body can be null — a 204 No Content has no body at all, and so do many 304s
"The catch block handles 5xx too"It catches HttpClientErrorException, which is 4xx only. A 500 throws HttpServerErrorException and propagates uncaught

The design point behind all three: RestTemplate is deliberately thin. It performs one HTTP call and translates the outcome — it adds no retries, no fallbacks, no null handling. Anything resilience-shaped is somebody else's job.

try {
    return restTemplate.getForEntity(url, String.class).getBody();   // may be null
} catch (HttpClientErrorException e) {          // 4xx only
    if (e.getStatusCode() == HttpStatus.NOT_FOUND) return "Customer not found";
    throw e;
} catch (HttpServerErrorException e) {          // 5xx — needs its own catch
    throw e;
} catch (ResourceAccessException e) {           // never reached the server
    throw e;
}
Memory hook: 4xx ⇒ HttpClientError · 5xx ⇒ HttpServerError · no response ⇒ ResourceAccess. RestTemplate never retries, and bodies can be null.

② Controller method parameters 2 misses

Q35 · Which annotations go on method parameters all four correct

All four — @RequestParam, @RequestHeader, @ModelAttribute, @RequestBody

Your answer: under-selected. There was no wrong option. The seventh "everything is true" question in the series.

The full set of parameter-binding annotations, by what they read:

AnnotationBinds from
@RequestParamquery string or form data
@PathVariablea URI template variable
@RequestBodythe request body, via a message converter
@RequestHeaderan HTTP header
@CookieValuea cookie
@ModelAttributea model attribute — form fields bound onto an object
@SessionAttribute, @RequestAttributesession / request attributes
@MatrixVariablematrix parameters in a path segment

The recognition rule: every @Request* and @Path* annotation is a parameter annotation — they name a part of the incoming request. The only outward-facing one is @ResponseBody, and it's not a parameter annotation at all. If it describes a piece of the request, it goes on a parameter.

@ModelAttribute is the one that looks different, because it also works on a method — there it pre-populates the model for every handler in the controller. On a parameter it binds form fields onto an object, which is what this question asked about.

Memory hook: Anything naming a part of the request binds a parameter. @ResponseBody is the only outward one.
Q43 · Which types can be controller method arguments

HttpSession, Principal, Locale — the wrong options are near-miss names

Your answer: you ticked "Language". You correctly rejected "Session" and "Request", so the filter worked on two of three.

This is a naming question dressed as a Spring question. Each wrong option is the plain English word for a real type:

OptionReal?The actual type
HttpSessionyes
Principalyesjava.security.Principal
Localeyesjava.util.Locale
Sessionnoyou mean HttpSession
Requestnoyou mean HttpServletRequest
Languagenoyou mean Locale

"Language" is the giveaway. Java's type for language-and-region has been called Locale since JDK 1.1 — there has never been a Language type anywhere in the JDK or Spring. It's the same family as DifferentOf, BiggerThan and @NoRollback: an everyday word standing in for a technical one.

Note that Principal and Locale come from the JDK, not Spring. Spring resolves them for you — Locale via the LocaleResolver, Principal from the servlet container or Spring Security.

Memory hook: HttpSession · Principal · Locale. The fakes are the plain-English versions: Session, Request, Language.

③ Converters & content negotiation 2 misses

Q15 · What an HttpMessageConverter is for

Converting between HTTP message bodies and Java objects

Your answer: three wrong options ticked — "transforms representations into resources", "is responsible for content negotiation", "relates to internationalisation". Each names a real Spring concern, but the wrong one.
ConcernActually handled by
Body ↔ object conversionHttpMessageConverter
Content negotiation — which media type to useContentNegotiationManager
InternationalisationMessageSource
View selection by media typeContentNegotiatingViewResolver

The distinction between the first two matters, because option 3 was close enough to be tempting: negotiation decides which media type; conversion does the actual work. The ContentNegotiationManager inspects the Accept header and answers "JSON"; the MappingJackson2HttpMessageConverter then turns your object into JSON bytes. Two steps, two components.

Where converters are used: @RequestBody (incoming — deserialise) and @ResponseBody / @RestController (outgoing — serialise). That's the message-conversion pipeline from round 1, and the converter is the thing doing the work in it.

Memory hook: Converter = body ↔ object. Negotiation = which media type. MessageSource = i18n. Three different components.
Q29 · The resolver that delegates rather than resolving

ContentNegotiatingViewResolver

Your answer: InternalResourceViewResolver and FreeMarkerViewResolver. Both resolve views directly — they're exactly what the question says the answer is not.

Read the stem's two clauses: "does not resolve views directly" and "delegates based on the client's requested representation". Only one resolver is a coordinator:

ResolverResolves how
ContentNegotiatingViewResolverdelegates to the others, then picks by Accept header
InternalResourceViewResolverdirectly — prefix + name + suffix → a JSP
FreeMarkerViewResolverdirectly — to a FreeMarker template
ThymeleafViewResolverdirectly — to a Thymeleaf template
BeanNameViewResolverdirectly — looks up a bean with that name

Its order is the tell: ContentNegotiatingViewResolver defaults to Ordered.HIGHEST_PRECEDENCE (well, Integer.MAX_VALUE - 10 in older configurations, but always first in the chain) — because it must run before the others in order to ask them all and choose between their answers. A resolver that delegates has to go first.

This connects to round 2's ViewResolver chain question: resolvers are tried in order, null means "pass". ContentNegotiatingViewResolver is the one that doesn't pass — it collects everyone's candidates and picks a winner.

Memory hook: "Delegates" / "based on Accept" ⇒ ContentNegotiatingViewResolver. It runs FIRST because it asks all the others.

④ WAR deployment & Servlet 3 bootstrap 2 misses

Q8 · Deploying a Boot app as a WAR

Three things needed — and you keep both the JAR mode and @SpringBootApplication

Your answer: "it can no longer run as a standalone JAR" and "@SpringBootApplication must be replaced with @Configuration". Both assume WAR support removes something. It only adds.
Required for WARWhy
Extend SpringBootServletInitializergives the container a WebApplicationInitializer to call
Override configure(SpringApplicationBuilder)names the primary source class — without it the container doesn't know what to bootstrap
Set <packaging>war</packaging>produces a WAR instead of an executable JAR
Replace @SpringBootApplicationno — you still need all three of its parts
Give up standalone modenomain() still works
@SpringBootApplication
public class DemoApplication extends SpringBootServletInitializer {

    @Override                                    // ← required for the container
    protected SpringApplicationBuilder configure(SpringApplicationBuilder app) {
        return app.sources(DemoApplication.class);
    }

    public static void main(String[] args) {     // ← still works standalone
        SpringApplication.run(DemoApplication.class, args);
    }
}

Both entry points coexist, and that's deliberate: developers run main() locally with embedded Tomcat, while CI produces a WAR for the shared container. The configure() override and the main() method are two doors into the same application.

One extra step the question didn't ask about but the exam sometimes does: mark the embedded server provided so it isn't packaged twice — spring-boot-starter-tomcat with <scope>provided</scope>.

Memory hook: Extend SpringBootServletInitializer + override configure() + packaging war. Keep @SpringBootApplication, keep main().
Q50 · Creating an ApplicationContext in a Servlet 3 app under-selected

Three valid routes — the only wrong one is FileSystemXmlApplicationContext

Your answer: under-selected. You correctly rejected the standalone context, then stopped short of the other two valid options.

Servlet 3.0 removed the need for web.xml: the container discovers ServletContainerInitializer implementations via META-INF/services, Spring registers SpringServletContainerInitializer, and that calls every WebApplicationInitializer on the classpath.

ApproachClassUse when
ConventionAbstractAnnotationConfigDispatcherServletInitializerstandard root + dispatcher setup
Manual, annotation configWebApplicationInitializer + AnnotationConfigWebApplicationContextcustom setup, multiple dispatchers
Manual, XML configWebApplicationInitializer + XmlWebApplicationContextmigrating a legacy XML app
FileSystemXmlApplicationContextstandalone only — no ServletContext awareness

The tell in the wrong option is the word Web. Web-capable contexts are AnnotationConfigWebApplicationContext and XmlWebApplicationContext; FileSystemXmlApplicationContext and ClassPathXmlApplicationContext have no Web in the name and no knowledge of a ServletContext. Same naming logic as DataSourceTransactionManager — the name tells you what it holds.

And the parent/child point that pairs with this: the convention-based initializer creates two contexts — a root (services, repositories, from getRootConfigClasses()) and a child dispatcher context (controllers, view resolvers, from getServletConfigClasses()). The child sees the root's beans; the root cannot see the child's. Putting @Service beans in the servlet config is the classic misconfiguration.

Memory hook: Servlet 3 = WebApplicationInitializer, no web.xml. Web-aware contexts have "Web" in the name. Root = services, child = controllers.

⑤ HTTP status categories 1 miss

Q38 · Which code families indicate errors inversion

4xx (client) and 5xx (server)

Your answer: 2xx and 3xxsuccess and redirection. You ticked the two families that specifically indicate no error.

The five families, and the one-word version of each:

FamilyMeansIn one wordExamples
1xxInformational"hold on"100 Continue
2xxSuccess"OK"200, 201, 204
3xxRedirection"go elsewhere"301, 302, 304
4xxClient error"your fault"400, 401, 403, 404, 405
5xxServer error"my fault"500, 502, 503

The mnemonic worth keeping is the whose-fault framing: 4xx = your fault, 5xx = my fault. It also explains the RestTemplate exception names — HttpClientErrorException for 4xx, HttpServerErrorException for 5xx — and the Actuator health mapping (DOWN → 503, a server-side problem).

On the inversion itself. This is the fourth time across your papers that a stem asking for the negative case got the positive answer. The fix is one deliberate step: before reading any option, say what you are hunting for. "I am looking for the two that mean something went wrong." Then 2xx and 3xx cannot survive contact with that sentence.

Memory hook: 1xx hold on · 2xx OK · 3xx go elsewhere · 4xx your fault · 5xx my fault. Only the last two are errors.

⑥ HATEOAS 1 miss

Q16 · What the HATEOAS auto-configuration provides also attempt #6

It replaces @EnableHypermediaSupport and supplies a HAL ObjectMapper

Your answer: you ticked "HATEOAS Security". On attempt #6 you under-selected on this same question; this time you added a wrong option. Same question, two different misses.
ProvidedNot provided
Replaces @EnableHypermediaSupportHateoasController — you write your own controllers
A HAL-configured ObjectMapper"HATEOAS Security" — security is Spring Security
LinkDiscoverers (client-side link parsing)
HAL-aware message converters

The ObjectMapper is the concrete difference, and you can see it in the output. With HAL support:

{ "id": 42, "status": "SHIPPED",
  "_links": { "self": { "href": "…/orders/42" } } }     ← Content-Type: application/hal+json

Without it, Jackson would serialise the raw RepresentationModel shape — "links": [ {"rel":"self","href":"…"} ] as a plain array, no underscore, application/json. That customised mapper is what makes the response HAL.

Both wrong options share a shape worth naming: they invent a component by gluing "HATEOAS" onto a familiar word. Same family as ConnectionHealthIndicator and @BeanConfiguration — a plausible compound with nothing behind it.

Proportion note: HATEOAS appears once or twice on the exam at most, and only at recognition level — EntityModel, CollectionModel, WebMvcLinkBuilder, HAL by default. Not worth deep study next to your Core and MVC gaps.

Memory hook: No @EnableHypermediaSupport needed + HAL ObjectMapper + LinkDiscoverers. You still write the controllers, and security is Spring Security.

The 9 facts, one line each

Round 3 in one pass
Before you re-sit — the two habits, in order (1) Name what you're hunting for, out loud, before reading the options. "Which families are errors" → say "I want the two that mean something went wrong". Q38 here, and three more on attempt #6, all died at this step. It costs five seconds. (2) Rule each option true/false on its own merits, then tick every true one. "All of them" has now been the answer seven times across your papers and banks. This one habit fixes both under-selection (7 marks in round 2, 2 here) and over-selection (~9 marks on attempt #10). (3) Then run all three MVC rounds. Round 1 (return types, the two pipelines, binding + status codes) · round 2 (arguments in / values out, RestTemplate, view technologies) · this one. 80 drills covering 46 misses — that is the whole section. (4) Use the clock. ~87 minutes spare. Both habits above fit inside them several times over.
I'm your teacher — ask me anything. Say "drill all three MVC rounds" to run the full 80 interleaved, "drill the inversions" for a set built entirely of which is NOT questions, or "drill the multi-selects" for select-all-that-apply only. When you're ready to re-sit, tell me the result and I'll build the review.
← Dashboard MVC round 1 MVC round 2 Lesson 11 · Spring MVC