Exam Drill #13 · 7 Sep 2026 · 23 to fix · 70 drills

Thirteenth attempt — two hours spent, second-worst score, and the answer isn't knowledge

37/60 = 62%. You used 1h 59m 36s — nearly triple attempt #12's 41 minutes — and still left two questions blank and scored 4 marks lower. That combination rules out the two explanations you'd reach for first: it wasn't rushing, and it wasn't the clock. 21 of the 23 misses are selection-count errors — ticking one option too many, or one too few — on questions where you knew the material. This page is built to fix that, and it carries 70 drills.

14
Over-selections (ticked a wrong extra)
7
Under-selections (stopped too early)
7
Already explained on this site
+9
Questions to pass
Official result · practice exam

62% — you did not pass this time

76% required to pass · 58/60 answered · 37 correct · time used 1h 59m 36s of 2h 10m
Spring Core 67%▼ 39 misses Data Management 67%▼ 33 misses Spring Security 67%— held1 miss Spring Boot 63%▲ 23 misses Spring MVC 60%▼ 403 misses Testing 56%▼ 194 misses

62% is your second-worst result in thirteen papers — only attempt #6's 58% is lower, and it ties attempt #3. The gap to a pass is +9 questions, the widest since #6.
Every section is now clustered between 56% and 67%. That flatness is itself the finding: there is no strong section left to lean on and no single catastrophic one to blame. Nothing is above 67%.
MVC fell 100% → 60%, the second consecutive paper confirming its clinic gain has fully decayed (the mixed set already showed 57%). Testing fell 75% → 56% three days after its clinic was written.

The clock changed completely — and it made things worse

40m 54s
Attempt #12 · 41/60
1h 59m 36s
Attempt #13 · 37/60
+192%
Time spent
−4
Marks

Every review on this site has told you to slow down. You did — emphatically. You used 92% of the available time, leaving 10 minutes instead of 89. And the score went down four marks.

Two questions were still left blank (Q11 and Q12) — with two hours on the clock. Both were single-answer questions you would answer correctly right now:

QQuestionAnswer
Q11What is Dependency Injection?"DI is a Pattern" — Spring is the framework that implements it
Q12REST is ______, and usually uses the ______ protocolstateless, HTTP — REST is an architectural style, not a protocol

Two free marks abandoned — 2 of the 9 you need. On a scored multiple-choice paper with no negative marking, a blank is strictly worse than a guess. There is never a reason to submit an unanswered question.

What the extra 79 minutes actually bought. Look at the failure shape below: 14 over-selections. Extra time spent staring at four plausible options does not produce certainty — it produces doubt, and doubt gets resolved by ticking one more box "to be safe." Longer deliberation is exactly the mechanism that generates over-selection. The fix is not more time or less time; it is a decision rule applied at constant speed.

21 of the 23 misses are selection-count errors, not knowledge gaps

This is the most important table on the page. It splits the 23 misses by how they were lost rather than by topic.

Failure modeMarksWhat happened
Over-selection14Every correct option ticked plus one wrong extra. Q3, Q13, Q17, Q21, Q24, Q25, Q26, Q31, Q36, Q42, Q44, Q51, Q56, Q60
Under-selection7Every tick right, but stopped before the last true option. Q29, Q35, Q37, Q49, Q53, Q54, Q58
Left blank2Q11, Q12 — no answer submitted, with 10 minutes spare
Genuine knowledge gaps0There is no question on this paper where you ticked only wrong options

Read that last row again. On all 21 answered misses you identified correct material. Not one question was a blank-slate topic. You are losing this exam on arithmetic, not on Spring.

The single rule that recovers most of it: rule every option true or false on its own merits, write the verdict down, then tick exactly the true ones. Never tick an option because it "might be included"; never stop ticking because "three feels like enough." An option you cannot rule true is false.

Note that over-selection and under-selection are opposite errors appearing on the same paper — which means neither is a habit you can correct by leaning one way. Only the per-option verdict works.

Seven of the twenty-three are already explained on this site — a record

Previous highs were four (#12) and three (mixed set). These are not merely similar questions; each has a page here that names the exact distinction being tested.

QTopicWhere it already livesSitting
Q53Advice types that accept a JoinPoint#6 Q22 · #12 Q39 — taught in review #54th
Q31Micrometer meter primitivesBoot clinic §③ — already marked "three times"4th
Q25@SpringBootTest + @ExtendWith on JUnit 5#6 Q28 · Testing clinic3rd
Q21permitAll() vs web.ignoring()Security clinic — has this exact drill3rd
Q49@WebMvcTest includes @JsonComponentTesting clinic — the list is spelled out3rd
Q13 · Q24Self-invocation bypasses the proxyData clinic · lesson 93rd
Q35Boot as a WAR on Tomcat / JettyBoot clinic · MVC round 32nd

Q53 is the one to sit with. "All four non-around advice types take an optional JoinPoint" is written verbatim in the closing list of review #12, eight days ago. The good news is real and worth naming: you no longer tick "None of the above" — the trap that cost this question in #6 and #12. You have moved the error from wrong to incomplete. One more step: tick all four.

Where the nine marks are

BucketMarksWhat it costs you
Answer every question2Zero study. Never leave a box blank — Q11 and Q12 were both easy
AOP & proxy mechanics5Q13, Q24, Q51, Q53, Q60 — one topic, four tables on this page
Transaction plumbing3Q17, Q44, Q58 — the enablement triad and the public rule
Re-drill the seven repeats7Material you already own; 20 minutes of drilling, not reading
Rule every option T/F21The ceiling if selection discipline were perfect — 62% → 100%

These overlap deliberately. You need +9. Answering the two blanks and fixing AOP alone is +7. Add the transaction triad and you are at +10 — a pass, without touching MVC, Testing, Boot or Security.

All 23, at a glance

QTopicWhat went wrongThe answer
Q3application.yml effectsTicked "a DataSource bean of type OracleDataSource"Boot auto-configures a DataSource (Hikari) from the properties
Q11What is Dependency Injection?Left blankDI is a pattern; Spring is a framework implementing it
Q12REST is ___, uses the ___ protocolLeft blankstateless, HTTP
Q13Which AOP mechanism supports self-invocationAlso ticked "JDK Dynamic Proxy"AspectJ only — weaving, not proxying
Q17Which two are required for transactionsTicked three — added "write an AOP advice"@Transactional + @EnableTransactionManagement
Q21Bypass the filter chain entirelyAlso ticked .ignoreAll() — invented methodweb.ignoring().antMatchers("/public/**")
Q24Limitations in both proxy typesTicked a CGLIB-only limitation (final methods/classes)Self-invocation · private methods
Q25@SpringBootTest statementsTicked "JUnit 5 must also add @ExtendWith"JUnit 4 needs @RunWith; JUnit 5 needs nothing
Q26getBean("myService")Ticked "returns null if not found"Throws NoSuchBeanDefinitionException
Q29True about MVC controllersUnder-selected — all four were truePOJO · no Servlet API · stereotype · testable
Q31Micrometer primitivesTicked "Memory Usage" / "CPU Usage"Counter · Gauge · Timer
Q35How to execute a Boot applicationUnder-selected — missed a WAR optionjava -jar · WAR on Tomcat · WAR on Jetty
Q36@Autowired statementsTicked "reflection for fields but not constructors/setters"Reflection is used for all three
Q37@Value statementsUnder-selected — three of four trueMethod args · SpEL · Maps
Q42@MockBean in an integration testTicked "the test still uses the real bean"@MockBean replaces the bean in the context
Q44@Transactional method visibilityAlso ticked "Any visibility level"public only
Q49What @WebMvcTest picks upUnder-selected — missed @JsonComponent@Controller · @RestController · @ControllerAdvice · @JsonComponent
Q51Statements about AOP advicesTicked "proceed() at most once"proceed() may be called many times
Q53Advice types supporting JoinPointUnder-selected — all four were true@Before · @After · @AfterReturning · @AfterThrowing
Q54Auto-provided controller argumentsUnder-selected — all four were trueErrors · Model · ServletRequest · ServletResponse
Q56Running SQL scripts before testsTicked SqlRunner / @SqlScript — both invented@Sql · ResourceDatabasePopulator.addScripts()
Q58Enabling declarative transactionsUnder-selected — three of four trueManager bean · @Transactional · @EnableTransactionManagement
Q60When is code modified for LTWAlso ticked "at runtime by JDK/CGLIB proxies"When classes are loaded by the classloader

Jump to a section

① AOP & proxies — 5 misses (the big one) ② Transactions — 3 misses ③ Core container & injection — 4 misses ④ Spring MVC — 3 misses ⑤ Testing — 4 misses ⑥ Boot & Actuator — 3 misses ⑦ Security — 1 miss

① AOP & proxies 5 misses · the biggest single bucket

Five of the twenty-three misses are one topic, and they sit on one axis: when and how the advice gets attached to your code. Get this table and Q13, Q24 and Q60 all fall at once.

Q13 & Q60 · Weaving strategies over-selected self-invocation · 3rd sitting

Three strategies, three different moments — and only one touches bytecode at load

Q13: you ticked AspectJ (right) and JDK Dynamic Proxy (wrong).
Q60: you ticked "when classes are loaded by classloaders" (right) and "at runtime by JDK/CGLIB proxies" (wrong). Both are the same error: adding the proxy option to a weaving question.
StrategyWhenMechanismSelf-invocation advised?
Compile-time weavingajc compilesAspectJ compiler rewrites the .classYes
Load-time weaving (LTW)ClassLoader loads the classJava agent + ClassFileTransformerYes
Runtime weaving (Spring AOP default)Bean instantiationJDK / CGLIB proxy wrapperNo

The one sentence that answers both questions: a proxy wraps the object; weaving changes the class. A wrapper can only see calls that arrive from outside, so this.inner() never reaches it. Woven bytecode is the object, so there is nothing to bypass.

Q60's exact wording matters. "Code is modified" — JDK and CGLIB proxies never modify your code; they generate a separate class that delegates to it. Your original .class file is byte-for-byte untouched. That option is disqualified by the verb in the stem.

LTW needs -javaagent:spring-instrument.jar plus @EnableLoadTimeWeaving; for transactions specifically, @EnableTransactionManagement(mode = AdviceMode.ASPECTJ) plus the spring-aspects dependency.

Memory hook: Compile = ajc. Load = classloader + agent. Runtime = proxy, and a proxy modifies nothing. Only weaving fixes self-invocation.
Q24 · Limitations shared by both proxy types over-selected

Two of the four are CGLIB-only — and the stem says both

You ticked a final option. Both correct answers (self-invocation, private) were also ticked — the mark went to the extra.

This question is answerable purely from how each proxy is built, without memorising a list. JDK proxies implement an interface. CGLIB proxies extend the class. Every limitation follows:

LimitationJDK (implements)CGLIB (extends)Both?
Self-invocation not advisedyesyesBOTH
private methods not advisedyesyesBOTH
final methods not advisedn/a — interfaceyesCGLIB only
final classes not proxiedn/a — interfaceyesCGLIB only

Why final is CGLIB-only: CGLIB works by subclassing and overriding. Java forbids overriding a final method and forbids extending a final class, so CGLIB is blocked. A JDK proxy never subclasses anything — it implements the interface — so final on the target class is irrelevant to it.

Why private is both: a private method is not visible to an interface or to a subclass. Neither strategy can see it. Spring AOP advises public method execution join points only.

Memory hook: JDK implements, CGLIB extends. final only blocks the one that extends. private and this.method() block both.
Q53 · Advice types that accept a JoinPoint under-selected 4th sitting

All four — and this time you didn't take the trap, you just stopped short

Your answer: under-selected. Genuine progress — you correctly rejected "None of the above", the option that cost this question in attempt #6 and again in #12. You simply didn't tick everything true.
AdviceFirst parameterControls execution?
@BeforeJoinPoint — optionalNo
@AfterJoinPoint — optionalNo
@AfterReturningJoinPoint — optional, then the returning bindingNo
@AfterThrowingJoinPoint — optional, then the throwing bindingNo
@AroundProceedingJoinPoint — requiredYes — must call proceed()

The whole question is one inheritance fact: ProceedingJoinPoint extends JoinPoint. So every advice type accepts a JoinPoint — @Around just needs the richer subinterface, because only it can call proceed(). There is no advice type that rejects introspection.

When the stem lists only the four non-around types, the answer is all of them. That is worth holding as a shape: a list of the four "after/before" advices with "None of the above" appended is a question where every named option is true.

Memory hook: All five advice types take a JoinPoint. @Around's is a ProceedingJoinPoint, which IS one. Tick all four; never "None of the above".
Q51 · Statements about AOP advices over-selected

proceed() may be called any number of times — including zero

You ticked "proceed() must be called up to 1 time only". You correctly rejected the invented @AfterFinally, and correctly took both true options.

ProceedingJoinPoint.proceed() is an ordinary method call. Calling it twice runs the target twice — that is exactly how retry advice is written. Calling it zero times means the target never runs, which is how caching and short-circuit authorisation advice work.

@Around("execution(* com.app..*(..))")
public Object retry(ProceedingJoinPoint pjp) throws Throwable {
    for (int i = 0; i < 3; i++) {
        try { return pjp.proceed(); }        // called up to THREE times
        catch (TransientException e) { /* retry */ }
    }
    throw new IllegalStateException("gave up");
}

The other three options, ruled individually:

OptionVerdictWhy
proceed() at most onceFALSEZero, one or many — retry and caching depend on it
@AfterFinally runs either wayFALSENo such annotation. The finally-semantics advice is @After
First param of @Around must be ProceedingJoinPointTRUERequired, and must be first
@AfterThrowing(throwing=...) narrows the match by exception typeTRUEThe declared parameter type filters which throws are advised

Spot the shape: the false option contains the absolute "must ... only", and the other contains an invented name. Both are recognisable without knowing AOP. Absolutes and invented names are your two most reliable eliminators — they have accounted for a miss on every paper in this series.

Memory hook: proceed(): 0, 1 or many. @After is the finally-advice — there is no @AfterFinally.

② Transactions 3 misses

Q17 & Q58 · Enabling declarative transactions over-selected under-selected

The same topic, missed in both directions on one paper

Q17 ("which two"): you ticked three — the two correct ones plus "write a Spring AOP advice".
Q58 ("what do you need to do"): you ticked two of three correct options. This pair is the clearest possible illustration of the selection problem — the knowledge is identical, the counting is not.

Three components, and the stem decides how many are on offer:

#ComponentProvidesIf missing
1@EnableTransactionManagement on a @Configuration classThe infrastructure — TransactionInterceptor + auto-proxy creator@Transactional is silently ignored
2A PlatformTransactionManager @BeanThe resource manager — JPA, JDBC or JTAFails at runtime when a transactional method is called
3@Transactional on the class or methodThe declaration of intentNothing is demarcated — no error, no transaction

Why Q17 says "two" and Q58 has "three". Q17's option list did not offer the manager bean, so only components 1 and 3 were available. Q58's did. The count in the stem is a fact about the option list, not about Spring. Rule each option on its own merits and both questions answer themselves — you never need to make the number come out.

The distractor you took on Q17: "write a Spring AOP advice to implement transactional behaviour." Spring's transaction support is built on AOP — that is why it feels right — but @EnableTransactionManagement registers TransactionInterceptor for you. The word that disqualifies the option is "write". Likewise, you never implement TransactionInterceptor yourself.

Under Spring Boot: TransactionAutoConfiguration supplies component 1, and the JDBC/JPA starters auto-configure component 2. You still write @Transactional yourself — Boot cannot guess which methods should be transactional.

Memory hook: Infrastructure (@EnableTransactionManagement) + manager bean + @Transactional. Boot gives you the first two, never the third.
Q44 · @Transactional and method visibility over-selected

public — and "Any visibility level" is the absolute that gives it away

You ticked "public" (right) and "Any visibility level" (wrong). Those two options are mutually exclusive — if any level worked, naming public would be pointless.

Use the contradiction. When an option list contains a specific answer and an "any / all / none" catch-all, they cannot both be true. Ticking both guarantees a zero. Pick one.

VisibilityProxy-based @TransactionalWhy
publicAppliedVisible through the interface and to a subclass
protectedIgnoredCGLIB could override it, but Spring's tx infrastructure does not process it
package-privateIgnoredNot part of the proxied contract
privateIgnoredCannot be overridden or intercepted by anything

The dangerous part, which the exam likes: Spring gives you no warning. @Transactional on a non-public method compiles, starts and runs — with no transaction at all. Same silent failure mode as self-invocation, and for the same reason.

The escape hatch is the same one as Q13: switch to AspectJ weaving (@EnableTransactionManagement(mode = AdviceMode.ASPECTJ)), which can advise non-public methods because there is no proxy — the target class itself is woven. Two conditions apply, and both are worth knowing precisely:

Where @Transactional sitsAspectJ pointcutAdvises private?
On the methodexecution(@Transactional * *(..))Yes — no visibility modifier in the expression
On the classexecution(public * ((@Transactional *)+).*(..))No — public is written into the pointcut

So annotating the non-public method directly is the only way to demarcate it — a class-level @Transactional will not reach it even under AspectJ. The mechanism is one constructor argument: AnnotationTransactionAspect builds its attribute source with new AnnotationTransactionAttributeSource(false) — publicMethodsOnly = false — where proxy mode uses the no-arg constructor and gets true.

And the mode attribute alone does nothing. AdviceMode.ASPECTJ needs spring-aspects on the classpath plus real weaving — the LTW agent (-javaagent:spring-instrument.jar) or compile-time weaving with ajc. Set the mode without weaving and no aspect is applied at all: you silently lose transactions everywhere, not just on the private method.

Version note for your exam. This site targets Spring 5.3, where proxy mode is public-only — so this question's answer is public. As of Spring 6.0, protected and package-visible methods are advised by class-based (CGLIB) proxies by default; interface-based proxies still require public. private is never advised by any proxy, in any version.

Memory hook: Proxy = public only, and silently. AspectJ reaches private — but only when the annotation is on the method, and only if weaving is actually configured.

③ Core container & injection 4 misses

Q11 · What is Dependency Injection? left blank

DI is a pattern. Spring is a framework that implements it.

Your answer: none submitted. With two hours on the clock. The correct option was sitting there — and even a blind guess is worth 25%.

The three wrong options are all category errors, and each is worth recognising by shape:

OptionVerdictWhat it actually describes
DI is a PatternTRUEA design pattern: dependencies supplied from outside
DI is a FrameworkFALSESpring is the framework. DI is framework-independent
Automatic Dependency Resolution for JavaFALSEMaven / Gradle resolving artifacts — build time, not runtime
Automatic Package Resolution for JavaFALSEHow the JVM resolves class names within packages

The related distinction the exam also asks: IoC is the broader principle ("don't call us, we'll call you" — the framework calls your code). DI is one specific form of IoC: the container supplies collaborators via constructor, setter or field. Spring implements both. Do not treat DI and IoC as synonyms in an exam question.

Memory hook: DI = pattern · IoC = principle · Spring = framework. Maven resolves artifacts; the container injects beans.
Q26 · context.getBean("myService") over-selected

A missing bean throws — Spring never hands you a null

You ticked "the code will return null if the bean is not found". You took both true options and correctly rejected "the bean is retrieved by type".

Spring's container is fail-fast by design. Returning null would push the failure to a later NullPointerException far from the cause. Every lookup failure has its own exception:

SituationResult
Bean name not definedNoSuchBeanDefinitionException
Lookup by type, several candidatesNoUniqueBeanDefinitionException
Found, but not the requested typeBeanNotOfRequiredTypeException
Bean foundThe instance — never null

The three overloads, and which one the snippet used:

Object    b = context.getBean("myService");                 // by NAME  → needs a cast
MyService s = context.getBean("myService", MyService.class); // by NAME + type → type-safe
MyService s = context.getBean(MyService.class);              // by TYPE  → throws if ambiguous

The snippet uses form 1, so "the bean is retrieved by type" is false — the string "myService" is a name. And getBean() is overloaded to return a specific type, which makes that option true.

Memory hook: Spring throws, it never returns null. NoSuchBeanDefinition = wrong name · NoUniqueBeanDefinition = ambiguous type · BeanNotOfRequiredType = wrong class.
Q36 · Statements about @Autowired over-selected

Reflection is used for all three injection styles, not just fields

You ticked "Spring uses reflection for field injection but not constructor and setter injection". You took both true options and correctly rejected "it is a JSR-330 annotation".

Think about what the container has to do. It holds a Class object and must produce an instance. There is no compiled call site anywhere — Constructor.newInstance(), Method.invoke() and Field.set() are all reflection. Field injection is not special; it just additionally needs ReflectionUtils.makeAccessible() to bypass private.

StatementVerdictWhy
Reflection for fields but not constructors/settersFALSEAll three use reflection
Often interchangeable with @InjectTRUEJSR-330's @Inject is handled by the same post-processor
It is a JSR-330 annotationFALSE@Inject is JSR-330. @Autowired is Spring's own
The dependency must be satisfied by defaultTRUErequired = true; relax with required = false or Optional<T>

The @Autowired / @Inject pair is worth pinning down because two of the four options turn on it. @Autowired is Spring, in org.springframework.beans.factory.annotation, and has a required attribute. @Inject is the JSR-330 standard, in javax.inject, and has no attributes at all — which is precisely why it cannot express required = false.

Memory hook: @Autowired = Spring, has required. @Inject = JSR-330, no attributes. Reflection drives constructor, setter AND field.
Q37 · Statements about @Value under-selected

Three of four are true — @Value does more than you gave it credit for

Your answer: under-selected. You correctly rejected the validation option — the only false one — and simply stopped before ticking everything true.

@Value resolves two syntaxes, and the difference is the most testable fact about it:

SyntaxNameResolved byExample
${...}Property placeholderThe Environment@Value("${app.name}")
#{...}SpEL expressionThe expression parser@Value("#{systemProperties['os.name']}")

Where it can be placed: fields, setter parameters, constructor parameters and @Bean method parameters — that last one is the "method arguments" option you left untaken. And #{${app.map}} — a placeholder nested inside a SpEL expression — injects a Map, which is the "inject into Maps" option.

@Bean
DataSource ds(@Value("${db.url}") String url) { ... }   // method ARGUMENT — true

@Value("#{${app.map}}")   Map<String,String> config;      // into a MAP — true
@Value("${app.servers}")  List<String> servers;           // comma-separated → List

The single false option — validation — is a layer error. Injection puts a value in; validation checks a value that is already there. Constraints come from Bean Validation (@NotNull, @Size, @Min) plus @Validated. Ask "does this option describe a different Spring feature?" — that is the shape of most false options in this bank.

Memory hook: ${} = property · #{} = SpEL. Fields, setters, constructor args AND @Bean method args. It injects; it never validates.

④ Spring MVC 3 misses · 100% → 60%

MVC has now fallen from 100% to 60% across two papers (the mixed set showed 57%), returning to almost exactly its pre-clinic level of 50%. The three clinic rounds worked — and then wore off, because they were never re-drilled. Note what the three misses are: one blank and two under-selections. None is an MVC knowledge gap.

Q12 · REST is ______, and usually uses the ______ protocol left blank

stateless, HTTP — and REST is not itself a protocol

Your answer: none submitted. Two of the four options could be eliminated in seconds — "stateful, REST" and "stateless, REST" both put REST in the protocol slot.

Eliminate on the second blank first. The stem says "uses the ___ protocol". REST is an architectural style, so any option naming REST as the protocol dies immediately — that removes two of four without thinking about statefulness at all.

PropertyValue
TypeArchitectural style — not a protocol, not a framework
StateStateless — the server keeps no client session between requests
ProtocolTypically HTTP
ResourcesIdentified by URIs
OperationsHTTP methods: GET, POST, PUT, DELETE, PATCH

"Stateless" precisely: every request carries everything needed to serve it. It does not mean the application has no state — the database is full of it. It means no client session state on the server between requests.

Memory hook: REST = stateless architectural STYLE over the HTTP protocol. If an option calls REST a protocol, it is wrong.
Q29 · True about Spring MVC controllers under-selected

All four were true — the "everything is true" question, again

Your answer: under-selected. Every tick you made was correct. There was simply nothing to reject.

All four statements describe the same single design decision — annotation-based controllers are plain objects — from four angles:

StatementWhy it is true
No base class or interface requiredHandler mapping is driven by annotations, not by type
No direct Servlet or Portlet API dependencyDispatcherServlet adapts request → method arguments
@Controller is a stereotypeA @Component meta-annotation, found by component scanning
They are testable artifactsFollows from the first two — instantiate with new, or use MockMvc

"All options correct" is a documented, recurring pattern in this bank — the MVC round 3 page already counted seven of them, and this paper adds two more on its own (Q29 and Q54). You have now lost more marks to this one question shape than to any single Spring topic.

The counting instinct is what fails here. "Four ticks feels like too many" is not evidence. When every option restates one idea from a different angle — as all four do here — that redundancy is the signal that they are all true, not a reason to choose between them.

Memory hook: Annotated controllers: POJO · no Servlet API · stereotype · testable. Four faces of one fact — tick all four.
Q54 · Arguments Spring provides to a handler method under-selected

All four again — Errors, Model, ServletRequest, ServletResponse

Your answer: under-selected. Second "all true" question on the same paper, and the second under-selection for the same reason.

The supported-argument list is long, and the exam draws from it repeatedly. Worth holding whole:

TypeGives you
Model / ModelMap / ModelAndViewAttributes exposed to the view
Errors / BindingResultValidation and binding errors
ServletRequest / HttpServletRequestThe raw request
ServletResponse / HttpServletResponseThe raw response
HttpSessionThe session (creates one if absent)
PrincipalThe authenticated user
Locale, TimeZoneResolved by the LocaleResolver
InputStream / Reader, OutputStream / WriterRaw body access
HttpEntity<T>, UriComponentsBuilder, SessionStatusBody + headers, URI building, session completion

The one positional rule the exam tests: Errors/BindingResult must be declared immediately after the validated @ModelAttribute or @RequestBody argument. Put anything between them and Spring cannot associate the two — you get a BindException (a 400) instead of your error-handling branch.

@PostMapping("/users")
String create(@Valid @ModelAttribute UserForm form,
              Errors errors,          // MUST be immediately after the validated arg
              Model model,
              HttpServletRequest req) { ... }
Memory hook: Model, Errors, request, response, session, Principal, Locale — all auto-provided. Errors goes directly after the object it validates.

⑤ Testing 4 misses · 75% → 56%, three days after its clinic

The Testing clinic was written five days ago and Testing is now your worst section. Two of these four misses are covered on that page by name. It confirms the pattern this site keeps documenting: a clinic that is read once decays within a week; the ones that hold are the ones that get re-drilled.

Q25 · @SpringBootTest and JUnit versions over-selected 3rd sitting

JUnit 4 needs @RunWith. JUnit 5 needs nothing.

You ticked "with JUnit 5 the class must also be annotated @ExtendWith(SpringExtension.class)". You also ticked the option stating the exact opposite — that @ExtendWith is contained in @SpringBootTest. Those two cannot both be true.

Use the contradiction, as on Q44. "You must add X" and "X is already included" are mutually exclusive. Whenever an option list contains a statement and its negation, exactly one is true — ticking both is a guaranteed zero. That pattern appeared twice on this paper.

JUnitExtra annotation needed?Why
JUnit 4Yes — @RunWith(SpringRunner.class)JUnit 4 runners are not composable, so it must be declared
JUnit 5No — nothing@SpringBootTest is meta-annotated @ExtendWith(SpringExtension.class)

This generalises to every slice. @WebMvcTest, @DataJpaTest, @JsonTest, @WebFluxTest — every Spring Boot test slice carries @ExtendWith(SpringExtension.class). Adding it yourself is redundant, never required.

Note that "redundant" is not "wrong": adding @ExtendWith explicitly compiles and runs fine. But the option said "must" — and that is the word that makes it false.

Memory hook: JUnit 4 → @RunWith(SpringRunner.class). JUnit 5 → nothing; every slice already carries SpringExtension.
Q42 · @MockBean in a @SpringBootTest over-selected

@MockBean replaces the bean in the context — that is its entire purpose

You ticked "the test will still use the real OrderService bean despite @MockBean". You took all three true options; the mark went to the extra tick.

Rule that option against the code in the stem. The test stubs when(orderService.getOrderById(1L)).thenReturn("Mock Order Details") and then asserts the response body is "Mock Order Details". If the real bean were used, the assertion could not pass — the option contradicts the snippet it is asked about.

AnnotationOriginEffect on the Spring context
@MockMockitoNone — plain unit tests; Spring never sees it
@MockBeanSpring Boot testReplaces the real bean with a mock
@SpyBeanSpring Boot testWraps the real bean — real methods unless stubbed

The performance fact the exam also asks: a @MockBean changes the context definition, so it produces a new, separately cached application context. Scatter different @MockBean combinations across many test classes and you rebuild the context repeatedly — the usual cause of a slow Boot test suite.

And @MockBean works on any Spring-managed bean — services, repositories, components, even controllers. The option restricting it to services was correctly rejected.

Memory hook: @Mock = Mockito only · @MockBean = replaces in the context · @SpyBean = wraps the real one. Each @MockBean combination = another cached context.
Q49 · What @WebMvcTest picks up under-selected 3rd sitting

Four in, two out — and @JsonComponent is the one you keep leaving behind

Your answer: under-selected. You correctly excluded @Repository and @Service. The list is spelled out in the Testing clinic, which has a drill asking exactly this.

One question decides everything: does this bean take part in handling an HTTP request? @JsonComponent registers Jackson serializers, which run during HTTP message conversion — so it is in. A @Service is business logic behind the web layer — so it is out.

Loaded by the sliceExcluded — mock it
@Controller, @RestController@Service
@ControllerAdvice@Repository, JPA, DataSource
@JsonComponentPlain @Component
Converter / GenericConverterTestRestTemplate (needs a real port)
Filter, HandlerInterceptor
WebMvcConfigurer, HandlerMethodArgumentResolver
MockMvc (auto-configured)

Two things worth knowing beyond the list: Spring Security auto-configuration is on inside the slice, so endpoints can return 401 — use @WithMockUser. And @WebMvcTest(OrderController.class) narrows to that one controller, but all @ControllerAdvice is still loaded.

Memory hook: @WebMvcTest = everything that touches an HTTP request. @JsonComponent IS in. Services and repositories are out — @MockBean them. Never TestRestTemplate.
Q56 · Running SQL scripts before test methods invented names

Two real answers — and you ticked two fabricated ones

You ticked SqlRunner.runScript() and/or @SqlScript. Neither exists in Spring. This is the failure mode the Testing clinic had driven to zero — it is back.
OptionReal?What it actually is
@SqlREALDeclarative — on a test class or method, with executionPhase
ResourceDatabasePopulator.addScripts()REALProgrammatic — register scripts, then execute(dataSource)
@SqlScriptINVENTEDThe plain-English expansion of @Sql
SqlRunner.runScript()INVENTEDA plausible-sounding class that does not exist

The tell is the same one as @Property, @NoRollback and @AfterFinally: the fake is the everyday-English version of the real name. @Sql runs SQL scripts, so @SqlScript sounds more descriptive — and that extra descriptiveness is exactly the signal. Spring's real names are terse: @Sql, @Rollback, @Commit, @Value.

And "Runner" is a loaded word in this exam. The real Spring runners are SpringRunner, SpringJUnit4ClassRunner and CommandLineRunner. There is no SqlRunner. When you see an unfamiliar XxxRunner or XxxTemplate, check it against the ones you can actually name.

@Test
@Sql(scripts = "classpath:data.sql",
     executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD)   // the default
void loadsSeedData() { ... }
Memory hook: @Sql declarative · ResourceDatabasePopulator programmatic. No @SqlScript, no SqlRunner — the wordier name is the fake one.

⑥ Spring Boot & Actuator 3 misses

Q3 · What an application.yml actually does over-selected

Boot configures a DataSource — it does not declare an OracleDataSource

You ticked "a DataSource bean is declared of type OracleDataSource". Both true options were taken, and you correctly rejected the Jetty distractor.

The distinction is configured vs declared as a type. Boot's DataSourceAutoConfiguration picks the connection-pool implementation from the classpath — HikariDataSource by default in Boot 2.x, then Tomcat JDBC, then Commons DBCP2. Your driver-class-name tells that pool which JDBC driver to load; it does not change the bean's type.

PropertyEffect
server.port: 8081Embedded Tomcat (Boot's default) listens on 8081
server.servlet.context-path: /bootApp is served at http://localhost:8081/boot
spring.datasource.*A HikariDataSource is auto-configured with those settings
driver-class-nameWhich JDBC driver the pool loads — not the bean type
jpa.hibernate.ddl-auto: create-dropSchema created at startup, dropped at shutdown

The Jetty option is worth naming too, because it is the same shape as Q35's NGINX option: switching containers is a dependency change, not a property. You exclude spring-boot-starter-tomcat and add spring-boot-starter-jetty. No line of YAML can change the embedded server.

Memory hook: Boot auto-configures a HikariDataSource from the properties. The driver class is a driver, not a bean type. Swapping the server is a dependency change.
Q31 · Micrometer primitives over-selected 4th sitting

A primitive is a meter type. "Memory Usage" is a meter instance.

You ticked "Memory Usage" and/or "CPU Usage". All three real primitives were taken. The Boot clinic already flags this question as having appeared three times.

The category test: a primitive is a kind of instrument; a metric is something you measured with one. "Memory usage" is measured — by a Gauge named jvm.memory.used. "CPU usage" is measured — by Gauges named system.cpu.usage and process.cpu.usage. Neither is an instrument.

PrimitiveAnswersTypical use
CounterHow many, monotonically increasingRequests processed, errors raised
GaugeWhat is the value right nowQueue depth, memory used, active connections
TimerHow many and how longHTTP latency, method duration
DistributionSummaryHow many and how big (non-time)Payload sizes, batch row counts
LongTaskTimerHow long, for tasks still runningBackground job duration

Two Gauge pitfalls the exam likes: a Gauge holds a weak reference to its source, so if the source is garbage-collected the gauge reports NaN — keep a strong field reference. And never tag with unbounded values like user IDs; cardinality explodes.

The layer above: a MeterRegistry holds the meters, one per monitoring system. Boot auto-configures a CompositeMeterRegistry when several micrometer-registry-* jars are present.

Memory hook: Counter · Gauge · Timer · DistributionSummary · LongTaskTimer are instruments. Memory and CPU usage are readings taken with a Gauge.
Q35 · How to run a Spring Boot application under-selected 2nd sitting

Three of four are true — both WAR options are real

Your answer: under-selected. You correctly rejected NGINX, which is the only false option. You just didn't take both WAR options.

Ruling the options one at a time:

OptionVerdictWhy
java -jar app.jarTRUEThe fat JAR's manifest points at JarLauncher
WAR on TomcatTRUEServlet 3.1+ container — SpringBootServletInitializer bootstraps it
WAR on JettyTRUEThe same WAR. Jetty is equally a servlet container
WAR on NGINXFALSENGINX is a web server / reverse proxy — it cannot execute a WAR

Why the Jetty option is easy to leave behind: Jetty is Boot's alternative embedded server, so it reads like the "wrong" choice. But this question is about the external deployment target — and there, Tomcat and Jetty are interchangeable. If Tomcat is true, Jetty is true.

The three things a traditional WAR requires:

StepWhy
<packaging>war</packaging>Build a WAR, not a fat JAR
Extend SpringBootServletInitializer and override configure()The container's ServletContainerInitializer uses it to build the context
Embedded container scope providedShading Tomcat into a WAR deployed on Tomcat causes a ClassCastException

One consequence worth holding: on an external container the WAR does not own the port, so server.port is ignored. And a Boot 3 WAR (Servlet 6 / jakarta) cannot deploy to Tomcat 9 (Servlet 4 / javax).

Memory hook: java -jar, or a WAR on any Servlet 3.1+ container — Tomcat AND Jetty. NGINX is a proxy and runs nothing. Mark the embedded server provided.

⑦ Spring Security 1 miss · the only section that held

Q21 · Bypassing the filter chain invented method 3rd sitting

web.ignoring() skips the chain — and ignoreAll() does not exist

You ticked antMatchers("/public/**").ignoreAll() alongside the correct security.ignoring().antMatchers(...). The Security clinic carries this exact drill: "What is the difference between permitAll() and web.ignoring()?"

Three of the four options were invented or misapplied, and all three are filterable without knowing the API — ignoreAll() and filtersNone() are simply not Spring Security methods, and anonymous() is real but does something else.

web.ignoring()permitAll()
Filter chainBypassed entirelyRuns in full
Authentication checkedNoNo
CSRF protectionGoneApplied
Security headersGoneApplied
Configured onWebSecurityHttpSecurity
Use forStatic assets onlyPublic endpoints

The structural tell: the two objects are different. web.ignoring() is configured on WebSecurity — outside the chain, which is why it can skip it. permitAll() is configured on HttpSecurity — inside the chain, which is why it cannot. Any option that chains a bypass method off antMatchers() alone is at the wrong level.

public void configure(WebSecurity web) {           // OUTSIDE the chain
    web.ignoring().antMatchers("/public/**");      // no filters run at all
}

protected void configure(HttpSecurity http) {      // INSIDE the chain
    http.authorizeRequests()
        .antMatchers("/public/**").permitAll();    // filters run, access granted
}

And anonymous(), the plausible one: it assigns an AnonymousAuthenticationToken to unauthenticated users. The chain still runs from end to end — the request just travels it as "anonymous" rather than as nobody.

Memory hook: web.ignoring() on WebSecurity skips the chain (losing CSRF and headers); permitAll() on HttpSecurity runs it and allows. No ignoreAll(), no filtersNone().

The 23 facts, one line each

Drill these, don't read them

Mixed drill — all seven sections, no topic headings

The section headings above tell you where to look. This set does not. Twelve questions drawn from the whole paper, in the order the exam would give them to you.

The change to make before the next attempt (1) Never leave a box blank. Q11 and Q12 were two free marks abandoned with 10 minutes spare, and you need nine. There is no negative marking — a guess strictly dominates a blank. (2) Rule every option true or false, then count. 21 of 23 misses were selection-count errors: 14 ticks too many, 7 too few. Write T or F beside each option before deciding how many to take. This one habit is worth more than every table on this page combined. (3) Watch for contradictory pairs. Twice on this paper you ticked an option and its negation — "public" with "any visibility level" (Q44), "you must add @ExtendWith" with "@ExtendWith is already included" (Q25). Both are automatic zeros, and both are visible without knowing the topic. (4) Absolutes and invented names, still. "must be called up to 1 time only" · @AfterFinally · @SqlScript · SqlRunner · ignoreAll() · filtersNone(). Four marks on this paper, filterable without any Spring knowledge. (5) Stop timing yourself, start pacing yourself. Two hours produced a worse score than 41 minutes. Aim for 60–75 minutes: enough to read each stem twice and rule each option, not so long that certainty decays into doubt. (6) Re-drill, don't re-read. Seven of these 23 are already explained on this site — a record, and it went up in the week you wrote two new clinics. Reading builds recognition; the exam tests recall.
A 25-minute routine before the next paper 10 min — the repeats. AOP section above (12 drills) covers four of the seven, including the JoinPoint question you have now met four times. 10 min — the two decaying clinics. Testing (75% → 56%) and MVC (100% → 60%). Both fell within a week of being written. 5 min — the mixed drill above. No headings, so you have to recognise the topic yourself — which is what the exam actually asks.
I'm your teacher — ask me anything. Say "drill the repeats" for a round built from the seven you've now missed more than once, "drill AOP" for the five-mark bucket, or "quiz me on the 23" for this whole attempt. If you want a targeted fix for the pattern behind 21 of these misses, ask for "a selection-discipline set" — questions where the only difficulty is deciding how many boxes to tick. A Spring Core clinic is still the one section without one, and Core carried 9 of the 23 misses here.
← Dashboard ← Review #12 Testing clinic MVC clinics Boot clinic