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.
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.
| Where | Question | Correct options |
|---|---|---|
| Attempt #5 | Spring Data comparison keywords | 4 of 4 |
| Attempt #9 | What spring.factories registers | 4 of 4 |
| Attempt #10 | Spring mock objects (3 of 5) | 3 of 5 |
| MVC round 2 | View technologies | 4 of 4 |
| MVC round 2 | Auto-provided handler arguments | 4 of 4 |
| Data clinic | EmptyResultDataAccessException | 4 of 5 |
| Here · Q35 | Parameter annotations | 4 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.
Q7 turns entirely on this, and it's the piece of RestTemplate you haven't met in rounds 1 or 2.
| Exception | Thrown when | Example |
|---|---|---|
HttpClientErrorException | 4xx — the client's fault | 404, 400, 403 |
HttpServerErrorException | 5xx — the server's fault | 500, 503 |
UnknownHttpStatusCodeException | a non-standard status code | a custom 6xx |
ResourceAccessException | no HTTP response at all | connection 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.
getForEntityHttpClientErrorException covers 4xxTake the three false claims one at a time, because each is a useful fact in its own right:
| Claim | Why 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;
}
@RequestParam, @RequestHeader, @ModelAttribute, @RequestBodyThe full set of parameter-binding annotations, by what they read:
| Annotation | Binds from |
|---|---|
@RequestParam | query string or form data |
@PathVariable | a URI template variable |
@RequestBody | the request body, via a message converter |
@RequestHeader | an HTTP header |
@CookieValue | a cookie |
@ModelAttribute | a model attribute — form fields bound onto an object |
@SessionAttribute, @RequestAttribute | session / request attributes |
@MatrixVariable | matrix 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.
HttpSession, Principal, Locale — the wrong options are near-miss namesThis is a naming question dressed as a Spring question. Each wrong option is the plain English word for a real type:
| Option | Real? | The actual type |
|---|---|---|
HttpSession | yes | — |
Principal | yes | java.security.Principal |
Locale | yes | java.util.Locale |
| Session | no | you mean HttpSession |
| Request | no | you mean HttpServletRequest |
| Language | no | you 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.
HttpMessageConverter is for| Concern | Actually handled by |
|---|---|
| Body ↔ object conversion | HttpMessageConverter |
| Content negotiation — which media type to use | ContentNegotiationManager |
| Internationalisation | MessageSource |
| View selection by media type | ContentNegotiatingViewResolver |
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.
ContentNegotiatingViewResolverInternalResourceViewResolver 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:
| Resolver | Resolves how |
|---|---|
ContentNegotiatingViewResolver | delegates to the others, then picks by Accept header |
InternalResourceViewResolver | directly — prefix + name + suffix → a JSP |
FreeMarkerViewResolver | directly — to a FreeMarker template |
ThymeleafViewResolver | directly — to a Thymeleaf template |
BeanNameViewResolver | directly — 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.
@SpringBootApplication| Required for WAR | Why |
|---|---|
Extend SpringBootServletInitializer | gives 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 |
@SpringBootApplication | no — you still need all three of its parts |
no — main() 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>.
FileSystemXmlApplicationContextServlet 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.
| Approach | Class | Use when |
|---|---|---|
| Convention | AbstractAnnotationConfigDispatcherServletInitializer | standard root + dispatcher setup |
| Manual, annotation config | WebApplicationInitializer + AnnotationConfigWebApplicationContext | custom setup, multiple dispatchers |
| Manual, XML config | WebApplicationInitializer + XmlWebApplicationContext | migrating a legacy XML app |
FileSystemXmlApplicationContext | — | standalone 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.
The five families, and the one-word version of each:
| Family | Means | In one word | Examples |
|---|---|---|---|
1xx | Informational | "hold on" | 100 Continue |
2xx | Success | "OK" | 200, 201, 204 |
3xx | Redirection | "go elsewhere" | 301, 302, 304 |
4xx | Client error | "your fault" | 400, 401, 403, 404, 405 |
5xx | Server 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.
@EnableHypermediaSupport and supplies a HAL ObjectMapper| Provided | Not provided |
|---|---|
Replaces @EnableHypermediaSupport | HateoasController |
A HAL-configured ObjectMapper | |
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.
HttpClientErrorException · 5xx ⇒ HttpServerErrorException · no response ⇒ ResourceAccessException. It never retries, and bodies can be null@RequestParam, @PathVariable, @RequestBody, @RequestHeader, @CookieValue, @ModelAttribute, @SessionAttribute, @MatrixVariable — anything naming part of the requestHttpSession, Principal, Locale. Session, Request and Language are not typesHttpMessageConverter = body ↔ object · ContentNegotiationManager = which media type · MessageSource = i18nContentNegotiatingViewResolver delegates to the other resolvers and picks by Accept — so it must be ordered firstSpringBootServletInitializer + override configure() + packaging war. Keep @SpringBootApplication and main()WebApplicationInitializer (no web.xml); web-aware contexts have "Web" in the name; root context = services, child = controllers@EnableHypermediaSupport + HAL ObjectMapper + LinkDiscoverers. No controller, no security