Exam Review #6 · 25 Aug 2026 · 25 to fix

Sixth attempt — 58%, and it is not a knowledge problem

You scored 35 / 60 = 58% — the lowest of the six. That reads like a collapse, and it isn't. Two things happened, and both of them are already solved problems. First: you took six days off. Attempt #5 was 19 Aug; this was 25 Aug, with no revision in between — and every section you didn't revisit fell, exactly as review #5 predicted. Second: at least 11 of the 25 misses are reading and answering errors, not gaps. Three questions asked "which is not…" and you answered the positive form. On eleven single-answer questions you ticked two or three options. The knowledge deficit here is roughly 10 marks. The technique deficit is 15.

58%
This attempt (35/60)
70%
Attempt #5 (42/60)
76%
Pass mark (46/60)
+11
Questions to pass
Official result · practice exam

58% — you did not pass this time

76% required to pass · 60/60 answered · 35 correct · time used 48m 59s of 2h 10m
Data Management 75%▲ 393 misses Testing 70%▼ 183 misses Spring MVC 67%— 01 miss Spring Core 57%▼ 146 misses Spring Boot 40%▼ 529 misses Spring Security 33%▼ 273 misses

Read the first row and the second-to-last row together — that is the whole story of this attempt. Data Management went 36% → 75% (+39): it is the one section review #5 told you to rebuild, and you did. Spring Boot went 92% → 40% (−52): it is the section review #5 told you to stop revising because it was "genuinely safe". Six days later it is your worst topic and accounts for 9 of the 25 misses. Nothing else in this dataset is as clean as that pair.
The clock, for the sixth time. 48m 59s of 2h 10m — 38% of your time, 81 minutes left unused, 49 seconds per question. You are still answering at roughly triple the pace the exam allows, and this is the attempt where that finally showed up as reading errors.

Section scores across the last four attempts

Read the last two columns as a controlled experiment: one section was revised, five were not.

Section#3 · 17 Aug#4 · 18 Aug#5 · 19 Aug#6 · 25 AugVerdict
Data Management60%91%36%75%Revised after #5 → recovered +39
Testing83%73%88%70%Drifting down without upkeep
Spring MVC60%57%67%67%Flat — the only stable section
Spring Core68%62%71%57%Never above 71 in six attempts
Spring Boot45%78%92%40%Not revised after #5 → lost 52
Spring Security33%100%60%33%100 → 60 → 33 in a week
What six attempts now prove, beyond argument. A review raises a section by 30–60 points within a day. That gain decays with a half-life of roughly three to four days and is essentially gone by day six. Spring Security is the clearest curve: 100% (day after its review) → 60% (day 2) → 33% (day 7). Spring Boot did the same thing one attempt later. Data Management proves the reverse direction works on demand. You do not have a learning problem. You have a schedule problem. Your six reviews now hold 124 corrected facts — that list is the exam, and it needs re-covering on a cycle, not once.
Your four failure modes this time — 25 misses, only ~10 of them knowledge
The single most damning question on this paper: Q26 Q26 asked which JPA repository method names are correctly formatted. You ticked deleteAgeLessThan(int age). This is the same question as Q27 in attempt #4, and you gave the same wrong answer. Review #4 contains a table with deleteAgeLessThan in it, marked "no — missing By", and a drill whose options are the identical four strings. You wrote the fix down seven days ago and then never re-read it. Q26 is the entire argument of this review compressed into one question.

The per-question protocol — worth ~15 marks, costs 40 of your 81 spare minutes

You have 130 minutes and you use 49. Spend them like this, on every single question, without exception:

  1. 1 · Read the stem twice and circle the polarity word. not, false, can't, except, invalid. If one is present, say out loud "I am looking for the wrong one." Three marks on this paper died here.
  2. 2 · Decide the answer count before you look at the options. "Which of the following is…" ⇒ one. "Which of the following are…" ⇒ two or more. Then tick exactly that many. If you find yourself ticking three on an "is" question, you have already lost the mark — pick the single best instead.
  3. 3 · Rule each option true/false out loud, one at a time. Never scan and pick. Every multi-select is really four independent true/false questions, and that is the format the marker uses. This is the fix for both under-selection and over-selection at once.
  4. 4 · Apply the three eliminators before guessing. (a) Does this name actually exist? — windows-version, replaceProdDb, @AutoConfigureDataSource, ActuatorController, "Logging Anonymization" were all inventions on this paper. (b) Is it an absolute? — "always", "only", "never", "not possible", "must explicitly declare every". (c) Is it the wrong layer? — @RestController for rendering, JAAS for storage, ICMP for endpoints, pom.xml for paths.

The 25 questions you failed

Your answer is reconstructed from the exported result — if a line looks wrong, tell me and I'll fix it. Click the topic to jump to the full explanation.

QTopicWhat you answeredThe answer
Q4JSR-250 annotationsUnder-selected — three of four were correctJSR-250 · enabled by <context:annotation-config> and <context:component-scan>
Q8Configuring a Boot test context"@ComponentScan" + "@TestConfiguration"Nothing — Boot finds @SpringBootConfiguration by walking up
Q9Valid @Profile usagesUnder-selected — three of four were validOn @Bean · !production on a class · {"dev","staging"}
Q10Handler return types a ViewResolver can resolve"Object"String · View · ModelAndView (also void)
Q11Configurable logging aspects"Logging Anonymization"Levels, pattern, file/console, rotation, colours, groups
Q13Which is not a valid log level"INFO" and "WARN" — answered the inverseEXCEPTION
Q14HATEOAS auto-configurationUnder-selected — missed one of the twoReplaces @EnableHypermediaSupport · hypermedia ObjectMapper
Q17CGLIB proxy visibility"private"public · protected · package-private
Q18Which can't conditionally render content"@PreAuthorize" and "@Secured" — answered the inverse@RestController
Q20What @Profile doesThree wrong options tickedRegisters a bean conditionally on the active profile
Q21Is /actuator/health exposed via JMX by default?"No"Yes — JMX default include is *
Q22Advice types that accept a JoinPoint"None of the above"All four — @Before, @After, @AfterReturning, @AfterThrowing
Q26Valid repository method names"deleteAgeLessThan(int age)"findByLastName · countByAgeGreaterThan
Q27Customising the Actuator path"Edit pom.xml" + "rename the endpoint classes"management.endpoints.web.base-path
Q28@SpringBootTest on JUnit 5Three wrong options ticked@SpringBootTest alone on the class — no @ExtendWith, no @RunWith
Q34Actuator endpoints provided out of the box"windows-version"health, info, loggers, beans, logfile — all real
Q35Stopping @DataJpaTest replacing the DataSource"replaceProdDb" + "@AutoConfigureDataSource"@AutoConfigureTestDatabase(replace = Replace.NONE)
Q36Which affirmation is falseTwo true statements ticked — answered the inverse"IoC is another name for DI" — DI is one way to do IoC
Q37Primary purpose of @SpringBootApplication"Defines a bean" + "defines security"Enables component scanning of its package and sub-packages
Q47EmptyResultDataAccessExceptionUnder-selected — four of five were correctEverything except "should throw a custom exception"
Q49Protocols Actuator exposes"ICMP"HTTP and JMX
Q51Overriding default security config"Disabling defaults is not possible; config is additive"A SecurityFilterChain bean replaces the defaults
Q56Metrics tag URL format"tag:KEY:VALUE" + "tag=KEY=VALUE"tag=KEY:VALUE
Q57User-detail storage mechanisms"JAAS"Database (JDBC) · LDAP · properties/in-memory
Q59Named parameters with JdbcTemplateThree wrong options tickedJdbcTemplate has no named params — use NamedParameterJdbcTemplate
Twelve of these twenty-five were already taught in an earlier review Q4 JSR-250 — #5 · Q17 CGLIB — #4, #5 · Q22 JoinPoint/advice — #5 · Q26 repository names — #4 (identical question, identical wrong answer) · Q28 SpringExtension — #3, #4 · Q36 IoC vs DI — #3, #4 · Q47 EmptyResultDataAccessException — #1, #5 · Q57 UserDetailsService — #3, #5 · Q21/Q27/Q34/Q49/Q56 Actuator — #1, #2, #5. That is 12 marks sitting in documents you have already written — and you need 11. Re-covering the six old checklists is, arithmetically, a pass.

Jump to a section

① Spring Boot & Actuator — 9 misses ② Spring Core — 6 misses ③ Testing — 3 misses ④ Spring Security — 3 misses ⑤ Data Management — 3 misses ⑥ Spring MVC — 1 miss

① Spring Boot & Actuator 9 misses

92% six days ago, 40% today, and five of the nine are Actuator — the single most repeated topic across all six of your reviews. Actuator is worth roughly 5 marks a paper and is entirely memorisable. Learn the two tables below and this section stops costing you the exam.

Q21 · Is /actuator/health exposed by default via JMX? Actuator · taught in #2, #5

Yes — JMX exposes everything by default; HTTP exposes almost nothing

Your answer: "No"you applied the HTTP rule to JMX. The two transports have opposite defaults, and that contrast is the entire question.

Two transports, two independent inclusion lists. This is the table that answers Q21, Q34 and Q49 all at once:

TransportPropertyDefault includeEffect
JMXmanagement.endpoints.jmx.exposure.include*every enabled endpoint is an MBean
HTTPmanagement.endpoints.web.exposure.includehealthonly health is reachable over HTTP

Enabled and exposed are different switches. shutdown is the only endpoint disabled by default, so even include=* won't publish it until you set management.endpoint.shutdown.enabled=true. And exposing health is not the same as showing its detail — management.endpoint.health.show-details defaults to never.

Version note for the exam: this is Boot 2.x behaviour, which is what 2V0-72.22 tests. In Boot 3.x, JMX is off unless spring.jmx.enabled=true.

Memory hook: JMX = everything (*). HTTP = health only. Enabled ≠ exposed. Only shutdown is disabled.
Q34 · Endpoints provided out of the box Actuator

windows-version does not exist — everything else on that list is real

Your answer: you ticked "windows-version". Note the question said "provided (not necessarily enabled)" — so logfile and beans count even though they're invisible by default.

Know the roster well enough to spot a fake. The ones that turn up in questions:

EndpointEnabled by defaultHTTP-exposed by defaultNote
healthyesyesthe only one, from Boot 2.1
infoyesnowas exposed in 2.0; populated by InfoContributors
beans, env, mappings, metrics, loggers, conditions, configprops, threaddump, heapdump, scheduledtasks, caches, httptraceyesnoopt in via exposure.include
logfileyesno404s unless logging.file.name is set
shutdownnonothe only disabled one

loggers is the one worth remembering for a second reason: it's read and writePOST /actuator/loggers/com.example with {"configuredLevel":"DEBUG"} changes a log level at runtime with no restart. That ties straight into Q11 and Q13 below.

Memory hook: ~20 real endpoints; only shutdown is disabled; only health is HTTP-exposed. Anything OS-flavoured is invented.
Q27 · Customising the Actuator path Actuator

management.endpoints.web.base-path — a property, never code and never the build file

Your answer: "edit pom.xml" and "rename the endpoint classes"both are wrong-layer answers, and the question had exactly one right option.

Everything about where Actuator lives is a property:

PropertyDefaultWhat it moves
management.endpoints.web.base-path/actuatorthe prefix for all endpoints
management.endpoints.web.path-mapping.<id>the endpoint idrenames one endpoint's path
management.server.portthe app portmoves Actuator to its own port
management.server.base-pathcontext path when on a separate port
management.endpoints.web.base-path=/admin
management.endpoints.web.path-mapping.health=status
# → GET /admin/status

There is no ActuatorController class. When an option names a class you have never seen in the docs, that is eliminator (a) from the protocol.

Memory hook: base-path moves them all · path-mapping renames one · management.server.port moves the whole lot to another port.
Q49 · Which protocols expose Actuator endpoints Actuator

HTTP and JMX — the same two transports as Q21

Your answer: you ticked "ICMP". ICMP is ping; it has no concept of an application endpoint. Wrong layer — eliminator (c).

Actuator has exactly two exposure technologies, and every Actuator property path names one of them: management.endpoints.web.* or management.endpoints.jmx.*. If a property or an option mentions any other transport, it is invented. TCP/IP is the layer HTTP runs on, not something Actuator speaks.

Memory hook: Two transports, two property namespaces: web and jmx. Nothing else.
Q56 · Filtering metrics by tag Actuator

tag=KEY:VALUE — equals separates the parameter, colon separates the pair

Your answer: "tag:KEY:VALUE" and "tag=KEY=VALUE"the first drops the query-parameter form entirely; the second can't be parsed, because the second = is ambiguous.

It is an ordinary query parameter whose value is a colon-joined pair, and you repeat it to AND several filters together:

GET /actuator/metrics/http.server.requests?tag=uri:/api/users&tag=status:200

Two related facts that show up alongside it: GET /actuator/metrics lists the available metric names, and GET /actuator/metrics/{name} without tags lists that metric's available tag keys and values — which is how you discover what you can filter on.

Memory hook: ?tag=KEY:VALUE — one =, then a :. Repeat the parameter to add filters.
Q11 · Which logging aspects Boot lets you configure

Everything except "anonymization" — that property does not exist

Your answer: you ticked "Logging Anonymization". Masking PII in logs is a custom Logback converter or a log pipeline; Boot has no knob for it.

Boot's logging surface is a fixed, learnable list. Anything on it is fair game in a question; anything off it is invented:

AspectProperty
Level (per logger or root)logging.level.root=INFO, logging.level.org.springframework=DEBUG
Output destinationlogging.file.name, logging.file.path
Patternlogging.pattern.console, .file, .level, .dateformat
Rotationlogging.logback.rollingpolicy.max-file-size, .max-history, .total-size-cap
Colourspring.output.ansi.enabled=always|detect|never
Groupslogging.group.sql=… then logging.level.sql=DEBUG

Two pitfalls that get asked: name the config file logback-spring.xml, not logback.xml, or Spring never processes <springProfile> and <springProperty>; and the rollingpolicy.* properties are silently ignored unless logging.file.name is set, because no rolling appender exists without a file.

Memory hook: Level · destination · pattern · rotation · colour · groups. No masking, no anonymisation.
Q13 · Which is not a valid log level polarity error

EXCEPTION — you ticked INFO and WARN

Your answer: "INFO" and "WARN"both are about as valid as a log level gets. You answered "which are valid". This is a free mark lost to the word not.

The ladder, most severe to most verbose, is short enough to recite:

LevelExists inNote
OFFallnothing is logged
FATALLog4j2 onlyLogback/SLF4J have no FATAL — it maps to ERROR
ERROR · WARN · INFO · DEBUG · TRACEallthe five you set with logging.level.*

Boot's default root level is INFO. Setting a level applies to that logger and everything below it in the dotted hierarchy. Invented levels to recognise on sight: EXCEPTION, CRITICAL, SEVERE (that one is java.util.logging, not SLF4J), VERBOSE, NOTICE.

Memory hook: OFF · FATAL(Log4j2) · ERROR · WARN · INFO · DEBUG · TRACE. Nothing else. Root defaults to INFO.
Q14 · What Spring HATEOAS auto-configuration provides

It replaces @EnableHypermediaSupport and configures a hypermedia ObjectMapper

Your answer: under-selectedyou took one of the two and stopped. Both surviving options were correct.

Add spring-boot-starter-hateoas and HypermediaAutoConfiguration gives you three things:

ProvidedWhat it means
Replaces @EnableHypermediaSupportyou never write the annotation yourself
A customised ObjectMapperserialises EntityModel/CollectionModel as HAL (the default media type)
LinkDiscoverersclient-side: find links inside a hypermedia response
@GetMapping("/orders/{id}")
public EntityModel<Order> getOrder(@PathVariable Long id) {
    return EntityModel.of(service.findById(id),
        linkTo(methodOn(OrderController.class).getOrder(id)).withSelfRel());
}

The distractors were an invented class (HateoasController — eliminator (a)) and a wrong layer ("HATEOAS Security" — that's Spring Security's job, eliminator (c)). Both distractors were the exact shapes the protocol filters.

Memory hook: HATEOAS auto-config = no @EnableHypermediaSupport + HAL ObjectMapper + LinkDiscoverers. You still write your own controllers.
Q37 · The primary purpose of @SpringBootApplication

The exam's answer: it enables component scanning of its own package and below

Your answer: "defines a bean" and "defines the application's security aspects"security is never @SpringBootApplication's job under any reading.

The annotation is exactly three annotations in a trench coat:

Meta-annotationEffect
@SpringBootConfiguration (a @Configuration)the class is a source of @Bean definitions — and the marker Boot's test bootstrapper searches for
@EnableAutoConfigurationloads auto-configuration classes conditionally from the classpath
@ComponentScanscans the annotated class's package and sub-packages

Be honest about this question: it is badly worded — auto-configuration is at least as defensible a "primary purpose". The exam's reasoning is that component scanning is the effect that depends on where you put the class, which is why the placement rule matters. The practical lesson isn't the answer, it's the technique: when two options are both arguably right, that is precisely the moment to pick one rather than tick both — and you had 81 minutes to think about it.

The placement rule it's really testing: put the class in the root package. Anything above it is never scanned, and tests that live above it fail with Unable to find a @SpringBootConfiguration (that's Q8).

Memory hook: @Configuration + @EnableAutoConfiguration + @ComponentScan. Root package, or nothing gets scanned.

② Spring Core 6 misses

57% — your lowest Core score in six attempts, and it has never once been above 71%. It's the biggest section on the paper, so it deserves the second-largest share of your time after Actuator.

Q4 · @PostConstruct, @PreDestroy, @Resource taught in review #5

JSR-250 annotations — and both XML tags enable them

Your answer: under-selectedthree of the four options were correct; you stopped at fewer. The only false statement was "Spring Framework embedded those annotations".

Two separate facts, and the question tested both:

AnnotationSpecPurposeSpring equivalent
@PostConstructJSR-250callback after DI completesinitMethod / InitializingBean
@PreDestroyJSR-250callback before destructiondestroyMethod / DisposableBean
@ResourceJSR-250inject by name@Autowired + @Qualifier
@InjectJSR-330inject by type@Autowired

All of them are processed by CommonAnnotationBeanPostProcessor, and both XML tags register it: <context:annotation-config/> turns on annotation processing, and <context:component-scan/> includes everything annotation-config does plus scanning. That "includes" relationship is why both options were correct — and it's a stock exam fact.

In Java config and Boot they're on automatically. One version trap: JSR-250 left the JDK in Java 11, so on Java 11+ outside Boot you need jakarta.annotation-api on the classpath.

Memory hook: @PostConstruct/@PreDestroy/@Resource = JSR-250, borrowed not invented. component-scan ⊃ annotation-config.
Q9 · Valid usages of @Profile

On a @Bean method, on a @Configuration class, negated, or a list — the only invalid form was exclude=

Your answer: under-selectedthree of four were valid. The single fake was @Profile({exclude="production"}): @Profile has one attribute, value, and it takes strings.

Every legal shape, in one block:

@Profile("dev")                       // single
@Profile({"dev", "staging"})          // OR — active if either is
@Profile("!production")               // NOT
@Profile({"!prod", "!staging"})       // AND of two negations

@Configuration @Profile("dev")        // class level: all beans inside
class DevConfig {
    @Bean @Profile("embedded")        // method level: this bean only
    DataSource ds() { … }
}

There is no exclude, no include, no name — negation is done with ! inside the string. And @Profile is itself just a specialised @Conditional(ProfileCondition.class), which is why it composes onto anything that produces beans, including @Component classes and other annotations.

Memory hook: Strings only. ! for NOT, an array for OR. Class level or method level. No exclude attribute.
Q20 · What @Profile actually does

It registers a bean conditionally — it never activates anything

Your answer: three wrong options ticked on a question with one correct answer. Each of the three was an absolute or a false restriction — protocol eliminator (b).

Take the four distractors one at a time, because each is a fact worth owning:

ClaimVerdictWhy
Registers a bean conditionally on the active profileTRUEthe definition
"Can only be used at class level"falseclass and @Bean method — Q9 showed both
"@Profile("dev") activates the dev profile"falseit consumes the active profiles; it never sets them
"The bean is created regardless"falsethen the annotation would do nothing
"Must be combined with @ComponentScan"falseworks on @Bean methods with no scanning at all

Activation is always external, and the exam asks how: spring.profiles.active=dev in properties · --spring.profiles.active=dev on the command line · SPRING_PROFILES_ACTIVE as an env var · @ActiveProfiles("dev") in tests · context.getEnvironment().setActiveProfiles(…) programmatically. If none is set, only beans with no @Profile plus those matching spring.profiles.default (which is default) are registered.

Memory hook: @Profile reads the active profiles. Something outside the code always sets them.
Q17 · CGLIB proxy visibility touched in #4, #5

public, protected, package-private — never private

Your answer: you ticked "private". Private methods can't be overridden by any Java subclass, so a subclass-based proxy is powerless over them.

The whole rule is just Java's overriding rules, because CGLIB proxying is subclassing: if a subclass could override it, CGLIB can intercept it.

MethodCGLIB (subclass)JDK proxy (interface)Reason
publicyesyesoverridable; on the interface
protectedyesnovisible to subclasses; not on an interface
package-privateyes (same package)nothe generated subclass sits in the same package
privatenonostatic dispatch — not overridable
final (any visibility)nonocannot be overridden
staticnononot dispatched on an instance

Three consequences the exam likes: final methods fail silently — no error at startup, the advice simply never runs; self-invocation bypasses the proxy at every visibility level, because this.method() never goes through the proxy reference; and CGLIB needs an accessible no-arg constructor on the target class in Spring 6 / Boot 3.

Pair this with the choice rule: Spring picks a JDK dynamic proxy when the target implements an interface, CGLIB otherwise — unless you force it with proxyTargetClass=true, which Boot does by default (spring.aop.proxy-target-class=true).

Memory hook: CGLIB = subclassing. If Java lets a subclass override it, CGLIB proxies it. Private, final and static are out.
Q22 · Which advice types accept a JoinPoint AOP · taught in review #5

All four of them — you answered "None of the above"

Your answer: "None of the above"the most expensive option on the paper, because it contradicts the four correct ones you'd otherwise have ticked. "None of the above" is an absolute: eliminator (b).

JoinPoint is available as an optional first parameter to every advice type. The only special case is @Around, which needs the subinterface:

AdviceFirst parameterControls execution?
@BeforeJoinPoint (optional)no
@AfterJoinPoint (optional)no
@AfterReturningJoinPoint (optional), then returningno
@AfterThrowingJoinPoint (optional), then throwingno
@AroundProceedingJoinPoint — required, and firstyes — must call proceed()
@Before("execution(* com.app.service.*.*(..))")
public void log(JoinPoint jp) {
    log.info("{} args={}", jp.getSignature().getName(), jp.getArgs());
}

@Around("execution(* com.app.service.*.*(..))")
public Object time(ProceedingJoinPoint pjp) throws Throwable {
    return pjp.proceed();          // may be called 0, 1 or many times
}

The two rules that get tested: JoinPoint must be first if declared at all — binding parameters from returning/throwing come after it; and ProceedingJoinPoint extends JoinPoint, so @Around gets getArgs()/getSignature()/getTarget() too, plus proceed().

Memory hook: All advice can take a JoinPoint. Only @Around takes — and requires — a ProceedingJoinPoint.
Q36 · Which affirmation is false polarity error

"IoC is another name for DI" — DI is one technique for achieving IoC

Your answer: you ticked two statements that were truethe question asked for the false one. Second polarity error on this paper.

The relationship is containment, not equivalence:

Inversion of ControlDependency Injection
What it isa broad principle: the framework, not your code, controls creation and flowone specific technique for realising it
Scopealso covers template methods, event callbacks, service locators, contextualised lookupconstructor, setter, field injection
RelationshipDI ⊂ IoC — every DI is IoC; not every IoC is DI

Spring's container is an IoC container that uses DI as its primary mechanism. The classic phrasing on the exam — "object coupling is bound at run time by an assembler object and is typically not known at compile time using static analysis" — is a true description of IoC, taken almost verbatim from the literature, so don't let its length make it look like the odd one out.

Memory hook: IoC is the principle; DI is the implementation. "Another name for" is the giveaway — they are not synonyms.

③ Testing 3 misses

88% → 70%. All three misses are annotation mechanics, and two of them are about knowing what isn't needed.

Q8 · Configuring the context for a Boot test

Nothing — Boot walks up from the test package and finds @SpringBootConfiguration

Your answer: "@ComponentScan" and "@TestConfiguration"both real annotations doing real jobs, neither of which is discovery.

@SpringBootTest is meta-annotated with @BootstrapWith(SpringBootTestContextBootstrapper.class). With no classes attribute, that bootstrapper uses SpringBootConfigurationFinder to search upwards from the test's own package until it hits a @SpringBootConfiguration — which @SpringBootApplication is meta-annotated with. Its @ComponentScan and @EnableAutoConfiguration then apply exactly as in production, which is why re-declaring them registers beans twice.

SituationWhat you do
App class at the root, tests in sub-packagesnothing — discovery just works
Two candidate @SpringBootConfiguration classes@SpringBootTest(classes = App.class)
Test lives above the app classmove the test, or set classes
Add extra beans for one testa nested @TestConfiguration class
Not a Boot app at all@ContextConfiguration + @ExtendWith(SpringExtension.class)

Know the two failure messages by name — they are stock answers: "Unable to find a @SpringBootConfiguration" (the walk never found one) and "Found multiple @SpringBootConfiguration annotated classes" (a duplicate on the classpath).

Memory hook: Boot test config is discovered, not declared. @TestConfiguration adds beans; it never replaces discovery.
Q28 · @SpringBootTest with JUnit 5 taught in #3, #4

@SpringBootTest alone, on the class — no @ExtendWith, no @RunWith

Your answer: three wrong options ticked, and the correct one — "use only @SpringBootTest" — was not among them. This is the clearest single case of spreading bets instead of committing.

Two independent things were being tested at once, and both distractor axes have to fail:

AxisRightWrong
Whereon the classon a method — @SpringBootTest is @Target(TYPE)
With whatnothing — since Boot 2.1 it meta-annotates @ExtendWith(SpringExtension.class)@RunWith(SpringRunner.class) is JUnit 4 and is silently ignored by Jupiter
@SpringBootTest                 // Boot 2.1+ on JUnit 5 — this is the whole thing
class UserServiceIT {
    @Autowired UserService service;
    @Test void loads() { assertNotNull(service); }
}

"Silently ignored" is the exam's favourite consequence: a JUnit 5 class carrying @RunWith looks like it runs, but Spring never bootstraps, so every @Autowired field is null. Note the mirror fact from earlier in this conversation — in plain Spring (no Boot), @ContextConfiguration does still need @ExtendWith(SpringExtension.class), or use @SpringJUnitConfig which bundles both.

Memory hook: Boot test = one annotation on the class. @RunWith is JUnit 4; @ExtendWith is redundant under Boot 2.1+.
Q35 · Stopping @DataJpaTest swapping in an embedded database

@AutoConfigureTestDatabase(replace = Replace.NONE)

Your answer: "replaceProdDb" and "@AutoConfigureDataSource"neither exists. Two invented names in one question: eliminator (a) would have left you a coin-flip between the two survivors.

@DataJpaTest is a composed annotation, and one of its parts is @AutoConfigureTestDatabase. You override the part, not the whole:

Replace valueBehaviour
ANY (default)always swap the DataSource for an embedded one (H2 → HSQL → Derby)
AUTO_CONFIGUREDswap only if the DataSource was itself auto-configured
NONEnever swap — keep the application's real DataSource
@DataJpaTest
@AutoConfigureTestDatabase(replace = Replace.NONE)   // e.g. run against Testcontainers Postgres
class UserRepositoryIT { … }

The reason it matters in practice — and the reason it's asked — is that leaving the default with H2 on the test classpath silently masks dialect-specific SQL: the tests pass and production breaks. Remember too that @DataJpaTest is @Transactional and rolls back each test by default.

Memory hook: @DataJpaTest = JPA slice + @AutoConfigureTestDatabase. Override the part: replace = Replace.NONE.

④ Spring Security 3 misses

33% — back to exactly where it was in attempt #3, having touched 100% in attempt #4. Only three questions, but the section is small, so each one costs a lot of percentage.

Q18 · Which can't conditionally render content polarity error

@RestController — you ticked the two that obviously can

Your answer: "@PreAuthorize" and "@Secured"the question asked which mechanism can't be used. Third polarity error on this paper, and the one that cost the most, because you clearly knew the material.

All three distractors do gate content; @RestController is a stereotype that says "return the body, not a view name" — it has nothing to do with authorisation at all:

MechanismWhere it worksNotes
@PreAuthorize("hasRole('ADMIN')")method / controllerSpEL; needs method security enabled
@Secured("ROLE_ADMIN")methodroles only — no SpEL
sec:authorize="hasRole('ADMIN')"Thymeleaf templatefrom thymeleaf-extras-springsecurity
<sec:authorize>JSP tag librarylegacy, still examinable
@RestController@Controller + @ResponseBody. Not security.

Worth keeping straight alongside it: @PreAuthorize/@PostAuthorize need prePostEnabled, @Secured needs securedEnabled, and @RolesAllowed (JSR-250) needs jsr250Enabled — all switches on @EnableGlobalMethodSecurity (Security 5) or @EnableMethodSecurity (Security 6, where prePostEnabled is on by default).

Memory hook: @PreAuthorize = SpEL · @Secured = roles only · sec:authorize = templates · @RestController = not security.
Q51 · Overriding the default security configuration

A SecurityFilterChain bean replaces the defaults — it never adds to them

Your answer: you ticked "Disabling default security configurations is not possible; custom configurations are always additive"a double absolute ("not possible", "always"), and it states the exact opposite of how back-off works.

The mechanism is Boot's standard conditional back-off: SpringBootWebSecurityConfiguration contributes a default chain only @ConditionalOnMissingBean(SecurityFilterChain.class). The moment you declare one, Boot's is not created — so whatever you didn't configure simply isn't there.

What you wantHowResult
Custom rules@Bean SecurityFilterChainreplaces the default chain entirely
No security at all@SpringBootApplication(exclude = SecurityAutoConfiguration.class)no security infrastructure is created
Several rule setsmultiple chains with @Order + securityMatcherfirst matching chain wins
@Bean
SecurityFilterChain chain(HttpSecurity http) throws Exception {
    http.authorizeHttpRequests(a -> a
            .requestMatchers("/public").permitAll()
            .anyRequest().authenticated())
        .formLogin(Customizer.withDefaults())
        .httpBasic(Customizer.withDefaults());
    return http.build();
}

The subtlety that made the fourth option correct too: excluding SecurityAutoConfiguration is genuinely how you remove Boot's security wholesale. And note the modern syntax — Security 6 removed .and() chaining and the no-arg .formLogin(); it's the lambda DSL or Customizer.withDefaults().

Memory hook: Declare a SecurityFilterChain and Boot backs off completely. Replaces, never supplements.
Q57 · Where Spring Security stores user details taught in #3, #5

Database (JDBC), LDAP, and in-memory/properties — JAAS is authentication, not storage

Your answer: you ticked "JAAS". Spring Security can integrate with JAAS to authenticate, but it ships no JAAS-backed UserDetailsService.

Everything hangs off one interface with one method — UserDetailsService.loadUserByUsername(String) — and the exam tests which implementations ship in the box:

Backing storeImplementationUse
Relational databaseJdbcUserDetailsManager / JdbcDaoImplproduction; default users + authorities tables
LDAPLdapUserDetailsManagerenterprise / Active Directory
In-memory / propertiesInMemoryUserDetailsManagertests, demos, prototypes
JAASJaasAuthenticationProvideran AuthenticationProvider, not a store
@Bean
UserDetailsService users() {
    return new InMemoryUserDetailsManager(
        User.withUsername("admin").password("{noop}secret").roles("ADMIN").build());
}

Two facts that ride along: UserDetailsManager extends UserDetailsService with create/update/delete, and the {noop} prefix is DelegatingPasswordEncoder's id — real deployments use {bcrypt}.

Memory hook: Three stores: JDBC · LDAP · in-memory. JAAS is a provider, not a store.

⑤ Data Management 3 misses

36% → 75%. This is the section you rebuilt after review #5, and it worked — the biggest single-attempt gain in the whole series. Keep it: the three remaining misses are small and specific.

Q26 · Valid repository method names identical question in review #4 — same wrong answer

Subject + By + property expressions joined with And/Or

Your answer: deleteAgeLessThan(int age)missing the By. You ticked this exact option in attempt #4, and review #4 has a table saying so.

The parse is mechanical, and every part is mandatory:

Method nameValid?Why
findByLastName(String)yessubject + By + one property
countByAgeGreaterThan(int)yescount subject + keyword
findByLastNameFirstName(…)noneeds And: findByLastNameAndFirstName
deleteAgeLessThan(int)nomissing By: deleteByAgeLessThan

Subjects: find, read, get, query, search, stream, count, exists, delete, remove. Keywords: Is/Equals, Not, LessThan/GreaterThan, Between, Like/StartingWith/EndingWith/Containing, In, IsNull, True/False, IgnoreCase, OrderBy…Asc/Desc, Top/First.

And the consequence that makes it examinable: property names must match entity fields, so findByLastNameFirstName is parsed as one property lastNameFirstName and, when it doesn't exist, fails at application startup — not at call time.

Memory hook: Always a "By". Multiple criteria always joined by And/Or. Bad names break at startup.
Q47 · EmptyResultDataAccessException taught in #1, #5

Four of the five options were true — you took fewer

Your answer: under-selected. The only false statement was the opinion one: "the method should throw a custom exception instead of returning null". Design opinions are almost never the exam's answer.

Everything about this exception, in the shape questions ask it:

JdbcTemplate call0 rows1 row>1 row
queryForObject(…)EmptyResultDataAccessExceptionthe objectIncorrectResultSizeDataAccessException
query(…)empty ListList of 1List of n
queryForList(…)empty ListList of 1List of n

The hierarchy is the reason it's useful: EmptyResultDataAccessExceptionIncorrectResultSizeDataAccessExceptionDataAccessExceptionRuntimeException. Because it's a distinct subclass you can catch "no rows" precisely, without swallowing connection failures or constraint violations — which is exactly what option 1 said. All of Spring's data access exceptions are unchecked, and the same hierarchy covers JDBC, JPA and Hibernate, so you can swap the technology without changing catch blocks.

Memory hook: queryForObject wants exactly one row: 0 ⇒ EmptyResult…, >1 ⇒ IncorrectResultSize…, query() ⇒ never throws.
Q59 · Named parameters with JdbcTemplate taught in review #2

JdbcTemplate has no named parameters — that's NamedParameterJdbcTemplate

Your answer: three wrong options ticked — case of the map keys, the return type, and "positional instead of named". The code's actual bug is the class doing the work.

Read the snippet's two halves against each other: the SQL uses :name, the parameters arrive as a Map — and JdbcTemplate understands neither.

JdbcTemplateNamedParameterJdbcTemplate
Placeholder? positional:name named
Argumentsvarargs / Object[]Map<String,?> or SqlParameterSource
update() returnsint — rows affected (never a boolean)
// wrong — JdbcTemplate cannot parse :name
jdbcTemplate.update("INSERT INTO users(name) VALUES (:name)", params);

// right
namedParameterJdbcTemplate.update("INSERT INTO users(name) VALUES (:name)",
        new MapSqlParameterSource("name", name));

NamedParameterJdbcTemplate wraps a JdbcTemplate internally (getJdbcOperations() reaches it) and translates named placeholders to positional ones before execution. Boot auto-configures both when a DataSource exists. The other useful SqlParameterSource is BeanPropertySqlParameterSource, which binds :name straight from a POJO's getName().

Memory hook: ? ⇒ JdbcTemplate · :name ⇒ NamedParameterJdbcTemplate. update() always returns an int row count.

⑥ Spring MVC 1 miss

67%, unchanged from attempt #5 — the only section that didn't move in either direction. One miss.

Q10 · Handler return types a ViewResolver can resolve

String, View, ModelAndViewObject is not a view contract

Your answer: you ticked "Object" alongside the correct three. A bare Object tells the resolver nothing about what it's holding.

What the DispatcherServlet does with each return type:

Return typeTreated as
Stringa logical view name → passed to the ViewResolver
Viewthe view itself — no resolution needed
ModelAndViewmodel and view (or view name) together
voidview name inferred from the request URL (RequestToViewNameTranslator)
Map / Modelmodel attributes; the view name is inferred as for void
Objectno view contract — with @ResponseBody it becomes the body instead

The distinction the exam is really drawing: view resolution vs. message conversion. Without @ResponseBody, a returned String is a view name; with @ResponseBody (or on a @RestController), the very same String is written straight to the response body by an HttpMessageConverter, and no ViewResolver is involved at all. That single annotation flips the meaning of the return value.

Memory hook: String / View / ModelAndView / void resolve to a view. @ResponseBody switches the whole pipeline to message converters.

Your close-the-gap checklist — attempt #6

The 25 facts, one line each
Do this next — the arithmetic says you already have the 11 marks (1) Stop learning new material. Start a review cycle. Twelve of these 25 misses are in checklists you have already written, and you need eleven marks. Before the next attempt, read the closing checklists of #1, #2, #3, #4, #5 and this one — 124 facts, about 40 minutes. Nothing else you can do with 40 minutes is worth as much. (2) Never leave more than three days between reviews. Six attempts show the decay half-life is three to four days. A section reviewed today is worth 30–60 points tomorrow and almost nothing by day six. (3) Actuator is 5 marks and is pure memorisation. Two tables — the exposure defaults and the endpoint roster — close Q21, Q27, Q34, Q49 and Q56 permanently. Lesson 16. (4) Run the four-step protocol on every question. Polarity word, expected answer count, option-by-option true/false, then the three eliminators. On this paper that was worth ~15 marks — more than the gap to a pass, twice over.

Your review schedule to the next attempt

WhenWhatTime
TodayThis review's 25 facts + every drill on this page45 min
TodayLesson 16 · Actuator — the two tables, out loud20 min
Day 2Checklists of reviews #1 and #220 min
Day 2Lesson 7 · AOP and Lesson 5 · Profiles — Core has never passed 71%40 min
Day 3Checklists of reviews #3, #4, #5 + Lesson 14 · Security40 min
Day 4All six checklists, fast pass — then the full mock, using at least 100 minutes2h 30
Day 5Next real attempt, protocol on every question

One rule for the next attempt, above all others: you must still be sitting there at the 90-minute mark. Every failure mode on this paper — polarity errors, ticking three options, stopping short on multi-selects — is what answering in 49 minutes looks like.

I'm your teacher — ask me anything. Want the merged rapid-fire round over all 124 misses from the six attempts (the highest-value drill available to you right now), an Actuator blitz, or a Spring Core rebuild? Just ask. Say "quiz me on the 25" for this attempt only, or "drill the polarity questions" for a set that is entirely "which is not / which is false".
← Dashboard ← Review #5 Mock Exam 📖 Glossary