42/60 again. But the section that had been your weakest for a month — Spring MVC — went from 50% to 100% with zero misses, the largest single-section gain of the entire series. You drilled three MVC rounds and the section is now finished. Spring Core fell to 58% and now carries 7 of the 18 misses, with AOP and SpEL the two clusters inside it. Plus two more polarity slips — the sixth and seventh times a "which is NOT" stem has been answered in the positive.
Four of six sections went up, and the top one went all the way. Spring MVC had never been above
75% in ten attempts and sat at 50% two days ago. After three drill rounds it scored 100% with no misses —
a +50 point move, the largest in the series. Data Management reached 86%, also its best.
Spring Core is now unambiguously the target. 58% is its worst since attempt #6, and it holds
7 of the 18 misses. Inside it, two clusters: AOP (3) and SpEL (2).
The clock slipped back. 35m 14s, down from 42m39s on each of the last two papers. That's
95 minutes unused, and the two polarity errors below are exactly what the extra time prevents.
| Section | Before its clinic | After | Since |
|---|---|---|---|
| Data Management | 57% | 75% | 81 → 82 → 86% |
| Spring Boot | 56% | 86% | 75% |
| Spring MVC (3 rounds) | 50% | 100% | — |
Three clinics, three immediate jumps, and the gains hold.
Data has stayed in the 75–86% band across four papers since its clinic. MVC took three rounds and 80 drills
— more than any other topic — and produced the biggest gain. The pattern is now established well enough to
predict: build the clinic, drill it, the section moves 18–50 points.
Spring Core has never had one. It is the last section without a clinic, and it is now your worst.
| Bucket | Marks | What it costs |
|---|---|---|
| ① AOP Q4 advice annotations · Q14 @Around · Q19 AspectJ syntax |
3 | One topic, one evening. Lesson 7. |
| ② Polarity slips Q7 "which is NOT auto-configured" · Q46 "which is INCORRECT" |
2 | Zero study. Say what you're hunting for before reading the options. |
| ③ SpEL Q16 where it can be used · Q37 standalone API |
2 | Lesson 5, one section. |
| ④ Already taught here Q10 fat jar (third time) · Q25 info endpoint · Q29 logging · Q12 random port |
4 | Re-drill the Boot clinic. ~20 minutes. |
Buckets ① and ② alone are 5 marks against a gap of 4 — one topic plus one habit. Add ③ and ④ and you are at 11, comfortably clear.
| Section | #7 | #8 | #9 | #10 | #11 · 29 Aug | Verdict |
|---|---|---|---|---|---|---|
| Spring MVC | 75% | 40% | 57% | 50% | 100% | Finished — 3 clinics |
| Data Management | 57% | 75% | 81% | 82% | 86% | Best of the series |
| Spring Boot | 64% | 71% | 56% | 86% | 75% | Holding post-clinic |
| Testing | 86% | 100% | 100% | 33% | 60% | Recovering |
| Spring Security | 100% | 100% | 75% | 33% | 50% | Only 1 miss — small section |
| Spring Core | 65% | 61% | 75% | 73% | 58% | Worst since #6 · no clinic yet |
| Overall | 70% | 70% | 73% | 70% | 70% | Flat total, moving parts |
@WebMvcTest — you ticked two that are. Q46 asked which statement is INCORRECT —
you ticked two that are correct. That is the sixth and seventh time across the series.SpelParser, SpelContext, "AssertJ
expression syntax", "friend methods". Down from 11 on attempt #10 — the existence check is working.Q2 contradicts itself. The option-level note
says "@Transactional on an interface works only with interface-based (JDK dynamic) proxies — NOT class-based
(CGLIB)". The summary at the bottom says the exact opposite: "On interfaces: works only with CGLIB
(class-based) proxies, not JDK dynamic proxies." The option-level note is the correct one. With a
CGLIB proxy Spring generates a subclass of your class, and Java does not inherit annotations from
interfaces onto a subclass — so an interface-level @Transactional is invisible. The Spring reference
documentation's advice is to annotate concrete classes, not interfaces, precisely because Boot defaults to
CGLIB.
Q25 states outdated behaviour. It says the
info endpoint is "exposed via both HTTP and JMX by default". That was true in Boot
2.0–2.4. Boot 2.5 removed info from the default HTTP exposure — since then only
health is exposed over HTTP. Your exam targets Boot 2.5, so if a question names a version, go with
health only; if it doesn't, this bank clearly expects the older answer. The Boot
clinic flags the same conflict.
Neither changes what you should have ticked on the day — but both are worth knowing so you don't memorise something wrong from the material.
Your answer is reconstructed from the exported result — if a line looks wrong, tell me and I'll fix it.
| Q | Topic | What you answered | The answer |
|---|---|---|---|
| Q2 | @Transactional facts | "On an interface, works only with class-based proxies" | Public methods only · default propagation REQUIRED |
| Q4 | Advice annotations | "@Component" | @Before · @AfterReturning |
| Q7 | What @WebMvcTest does not configure | "Jackson" + "Caching" — both ARE configured | Transaction management |
| Q8 | REQUIRES_NEW when the inner fails | Three wrong options ticked | Both roll back — the exception still propagates |
| Q10 | Fat jar vs regular jar | "The fat jar is smaller" — third time | Executable · manifest · all dependencies |
| Q11 | @MockBean | "Same as @Mock, different library" | Adds a mock to the ApplicationContext |
| Q12 | Testing on a random port | "No webEnvironment" + "server.port=8080" | RANDOM_PORT · server.port=0 |
| Q14 | What the @Around aspect does | "Batches DB operations" + "makes methods idempotent" | Starts and commits a transaction around the call |
| Q16 | SpEL statements | "Can only be used inside annotations" | Also XML, and it supports literals |
| Q17 | Authentication mechanisms | Under-selected — five of six were correct | X.509 · Digest · Basic · OAuth2/OIDC · Form (not LDAP) |
| Q19 | Which expression syntax Spring AOP uses | "AssertJ" + "JS" — neither exists | AspectJ pointcut expressions |
| Q25 | The info endpoint | "Custom data can't be supplied" | Via info.* properties or InfoContributor |
| Q29 | Default logging implementation | "Java Util Logging" + "Log4J2" | Logback |
| Q30 | Registering a BeanPostProcessor | Non-static @Bean + @Bean without @Configuration | A static @Bean method |
| Q35 | Starter dependency management | "Each starter must declare its own version" | Versions come from the Boot BOM |
| Q37 | SpEL standalone | "SpelParser/SpelContext" (invented) + "No, only via @Value" | ExpressionParser + EvaluationContext |
| Q46 | Which @WebMvcTest statement is incorrect | Two correct statements ticked | You don't need @ExtendWith — it's built in |
| Q54 | What Java 8 interfaces can declare | "Regular method implementation" + "friend methods" | static · constants · nested types · default |
The largest single cluster on the paper, and the cheapest to close. AOP is one self-contained topic: five advice types, a handful of designators, one proxy model.
@Before and @AfterReturning — @Aspect and @Component mark the class@Component.
The question separates class-level annotations from method-level ones, and
both wrong options are class-level.| Level | Annotations | Purpose |
|---|---|---|
| Class | @Aspect | "this class contains advice and pointcuts" |
| Class | @Component | "make it a Spring bean" — required, or Spring never sees the aspect |
| Method | @Before · @After · @AfterReturning · @AfterThrowing · @Around | the five advice types |
| Method | @Pointcut | a named, reusable pointcut expression |
Both class-level annotations are needed together, and that's a stock exam point:
@Aspect alone does nothing, because Spring only weaves aspects that are beans. You need
@Component (or a @Bean method) as well.
And the version fact that pairs with it: all these annotations come from AspectJ
(org.aspectj.lang.annotation), not from Spring. Spring interprets them with its own proxy runtime —
which is exactly what Q19 below is about.
@Around transaction aspect achievesRead the advice body and the answer is written there:
@Around("execution(* com.example.service.*.*(..))")
public Object manageTransaction(ProceedingJoinPoint jp) throws Throwable {
System.out.println("Transaction started."); // ← before
Object result = jp.proceed(); // ← the real method
System.out.println("Transaction committed."); // ← after
return result;
}
The general principle the distractors miss: AOP is a mechanism for inserting code, not a source of behaviour. It cannot batch, synchronise or make anything idempotent unless you write that code in the advice. If an option claims AOP does something "automatically", ask where that code would live.
And the connection worth making: this is a simplified version of what Spring's own
@Transactional does. TransactionInterceptor is an @Around-style
MethodInterceptor that begins a transaction, calls proceed(), and then commits or
rolls back. Understanding this one aspect explains @Transactional's proxy limitations too.
One flaw in the code worth spotting: there is no try/catch, so if the method throws,
"Transaction committed" never prints and nothing rolls back. A real @Around transaction aspect needs
a catch.
The genuinely interesting distractor was SpEL, and the distinction is worth owning because both are "Spring expression languages":
| Language | Used for | Looks like |
|---|---|---|
| AspectJ | AOP pointcuts only | execution(* com.example.service.*.*(..)) |
| SpEL | @Value, @Cacheable(key=…), @PreAuthorize, @ConditionalOnExpression | #{2 * T(Math).PI} |
Why Spring borrowed AspectJ's syntax rather than inventing one: AspectJ already
had a mature, well-specified pointcut language, and Spring wanted aspects to be portable between proxy-based
Spring AOP and full AspectJ weaving. So aspectjweaver is a required runtime dependency —
Spring uses it to parse and match expressions, even though it never does byte-code weaving.
The designators Spring AOP supports: execution, within,
args, this, target, @annotation, @within,
@target, @args, plus Spring's own bean(…). Spring AOP supports only
method-execution join points — AspectJ's call, get, set and
initialization throw IllegalArgumentException.
aspectjweaver is required). SpEL is for @Value, caching, security — never pointcuts.| Where | Example |
|---|---|
| Annotations | @Value("#{2 * 60}") |
| XML configuration | <property name="timeout" value="#{30 * 1000}"/> |
| Programmatically | new SpelExpressionParser().parseExpression(…) |
| Spring Security | @PreAuthorize("hasRole('ADMIN')") |
| Caching | @Cacheable(key = "#id") |
| Spring Data | @Query("… :#{#user.id}") |
And the operators, since the other distractor claimed maths was missing:
arithmetic + - * / % · relational == != < > <= >= · logical
and or not (or && || !) · ternary ?: · Elvis ?: ·
safe navigation ?. · type reference T() · projection ![] · selection
?[].
Literals are supported too: strings 'hello', numbers, true,
false, null. That was the second correct option.
#{} — annotations, XML, security, caching, and standalone. Full arithmetic included.ExpressionParser + EvaluationContext — spring-expression is a standalone libraryExpressionParser parser = new SpelExpressionParser();
String s = parser.parseExpression("'Hello ' + 'World'").getValue(String.class);
User u = new User("Alice", 30);
EvaluationContext ctx = new StandardEvaluationContext(u);
boolean adult = parser.parseExpression("age >= 18").getValue(ctx, Boolean.class);
The naming rule that would have caught the fake: the interfaces are
generic — ExpressionParser, EvaluationContext — and the implementations carry
the prefix: SpelExpressionParser, StandardEvaluationContext.
SpelParser and SpelContext are truncations — real Spring names are longer and
more explicit, not shorter.
Two facts worth carrying: spring-expression depends only on
spring-core, so it runs in any plain-Java program; and for untrusted input use
SimpleEvaluationContext rather than StandardEvaluationContext, which exposes
reflection, method invocation and constructor calls.
BeanPostProcessorstatic @Bean method in a @Configuration class@Bean method and a @Bean without
@Configuration. Both work "in practice" and both carry the same ordering
risk — which is exactly what the question is about.The problem is a chicken-and-egg ordering conflict. A
BeanPostProcessor must exist before other beans are created, because it processes them. But
a non-static @Bean method requires its enclosing @Configuration class to be
instantiated first — and that class is itself a bean that wants post-processing.
@Configuration
public class InfrastructureConfig {
@Bean
public static LoggingBeanPostProcessor loggingBPP() { // ← static
return new LoggingBeanPostProcessor();
}
}
static breaks the cycle — Spring can invoke a static method without
instantiating the class, so the BPP is available very early. Declare it non-statically and Spring logs:
BeanPostProcessor [X] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)
The same rule applies to BeanFactoryPostProcessors — which is why
PropertySourcesPlaceholderConfigurer and CustomScopeConfigurer are conventionally
declared static too. Anything that processes other beans should be a static @Bean
method.
One consequence to remember: static @Bean methods are not CGLIB-intercepted,
so calling one from another method creates a new instance rather than returning the singleton. Use static only
for post-processors, never for ordinary beans other beans depend on.
static @Bean method. Static breaks the ordering cycle.default methodsfriend is C++ — Java has no such keyword. And a body in an interface requires
default or static.| Member | Allowed? | Since |
|---|---|---|
| Abstract methods | yes | 1.0 |
Constants (implicitly public static final) | yes | 1.0 |
Nested types (implicitly public static) | yes | 1.0 |
default methods | yes | Java 8 |
static methods | yes | Java 8 |
private methods | yes | Java 9 |
| A regular (non-default, non-static) body | no | — |
| "friend" methods | no such concept in Java | — |
Why default was added is the Spring-relevant part: it lets an
interface gain new methods without breaking every existing implementation. The JDK used it to add
Collection.stream() and Comparator.reversed() — and Spring used the same trick in
5.0, making both BeanPostProcessor methods default so implementations only override
the one they care about. That connects directly to Q30 above.
Two rules worth having: a default method cannot redeclare an Object
method (equals, hashCode, toString) — compile error; and
static interface methods are not inherited — you must qualify them with the interface
name.
default + static. Java 9 adds private. No "friend" — that's C++.33% → 60%, recovering. Two of the four are polarity slips, not knowledge.
@WebMvcTest does NOT auto-configure polarity@WebMvcTest definitely does configure. The stem asked for the exception.| Loaded by @WebMvcTest | NOT loaded |
|---|---|
@Controller, @ControllerAdvice, @JsonComponent | @Service, @Repository, @Component |
WebMvcConfigurer, Filter, HandlerInterceptor | DataSource, JPA, transaction management |
Converter, HandlerMethodArgumentResolver | full @EnableAutoConfiguration |
Jackson (an ObjectMapper) · templating · caching · MockMvc |
The rule behind the slice: @WebMvcTest loads what the web
layer needs — anything a controller might touch while producing a response. Jackson serialises the body,
templates render views, caching annotations may sit on web components. What it excludes is the
persistence layer, which is why you mock the service with @MockBean.
On the polarity slip. This is the sixth across your papers. The fix is one sentence said before you look at the options: "I am hunting for the one thing that is NOT there." With that in mind, Jackson and caching cannot survive — you know they're loaded.
@WebMvcTest statement is INCORRECT polarity@ExtendWith(SpringExtension.class) — it's built inSince Boot 2.1, every test-slice annotation is meta-annotated with
@ExtendWith(SpringExtension.class):
@WebMvcTest(UserController.class) // ← this is the whole thing
class UserControllerTest {
@Autowired MockMvc mockMvc;
@MockBean UserService userService;
}
Adding @ExtendWith yourself is harmless but redundant. The same is true of
@SpringBootTest, @DataJpaTest, @JsonTest and the rest — one annotation
is always enough.
Two polarity slips on one paper is the signal to change something mechanical. Both stems contained a capitalised or emphasised negative — NOT, INCORRECT — and both were answered in the positive. Before reading any option, state the target out loud. You have 95 spare minutes; this costs five seconds a question.
@MockBean is for@Mock does not@MockBean exists.@Mock (Mockito) | @MockBean (spring-boot-test) | |
|---|---|---|
| Creates a mock | yes | yes |
| Knows about the Spring context | no | yes |
| Replaces an existing bean | no | yes |
| Injected into other beans | no | yes |
| Creates a bean if none exists | n/a | yes |
The practical difference: @Mock gives you an object you must wire in
by hand — fine for a plain unit test. @MockBean registers a bean definition, so the
controller Spring instantiates receives the mock. That's what makes it usable inside
@WebMvcTest.
The performance pitfall worth knowing: each distinct combination of @MockBean types
produces a different context cache key, so a new ApplicationContext is built. Scattering many different mock
combinations across test classes destroys context caching and slows the suite badly.
Version note: in Spring Framework 6.2 / Boot 3.4 this moved to
@MockitoBean in spring-test, with @MockBean deprecated. Your exam targets
Boot 2.5, where @MockBean is correct.
@SpringBootTest(webEnvironment = RANDOM_PORT) — or server.port=0server.port=8080". The first gives you no server at all; the second
is the opposite of random.Two genuinely equivalent routes, and both were correct:
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class MyIT {
@LocalServerPort int port;
@Autowired TestRestTemplate restTemplate;
}
# or — src/test/resources/application.properties
server.port=0 # 0 means "any free port" at the servlet-container level
server.port=0 is the underlying mechanism, and that's why the two are
equivalent: RANDOM_PORT sets exactly that property for you. Port 0 is a long-standing TCP convention
meaning "let the OS pick a free one".
And the default that made the first option wrong: @SpringBootTest defaults to
MOCK — a mock servlet environment with no server and no port, which is why
TestRestTemplate isn't auto-configured there. That fact has now appeared on three of your papers.
server.port=0 — the first sets the second. Default is MOCK: no server, no port, no TestRestTemplate.86% → 75%, still well above where it was before its clinic. All four of these are in the Boot clinic.
| Original jar | Fat jar | |
|---|---|---|
| Size | small | strictly larger |
Main-Class | yours or absent | org.springframework.boot.loader.JarLauncher |
Start-Class | absent | your @SpringBootApplication class |
| Dependencies | none | BOOT-INF/lib/*.jar, nested |
java -jar | no | yes |
Missed three times, so here's a way to make it stick that isn't a table: "fat" is the name. A fat jar is called fat because it is bigger — it has eaten all its dependencies. If an option says a fat jar is smaller, the option contradicts the name in the question.
The mechanism, once: the JDK class loader cannot read a jar nested inside another jar. So
Boot ships JarLauncher and LaunchedURLClassLoader inside the archive, points
Main-Class at the launcher, and records your real main class as Start-Class.
You have now missed both halves of the same two-layer fact, which is why it's worth pinning down properly:
| Question | Asks about | Answer |
|---|---|---|
| Attempt #9 Q2 | the API Spring's own code logs through | Commons Logging (JCL) |
| This paper Q29 | the implementation that writes output | Logback |
Spring's own code
→ Commons Logging (the API it compiles against) ← attempt #9's answer
→ Logback (the default implementation) ← this paper's answer
or Log4J2, or JUL (if you swap the starter)
Read which layer the stem means. "Used for internal logging" / "logging API" ⇒ Commons Logging. "Default logging implementation" / "what writes the output" ⇒ Logback. Facade versus implementation is the whole distinction, and the same shape as SLF4J-vs-Logback.
Switching: exclude spring-boot-starter-logging and add
spring-boot-starter-log4j2. Without the exclusion both bindings are on the classpath and Logback
silently wins.
info endpoint Boot clinic §1info.* properties or InfoContributor| Source | How |
|---|---|
| Static properties | info.app.name=…, info.app.version=… |
| Build information | the Boot Maven/Gradle plugin generates build-info.properties |
| Source control | git.properties from the git-commit-id plugin |
| Anything dynamic | a @Component implementing InfoContributor |
Remember it as the read-only twin of loggers: info
exposes arbitrary data you supply and changes nothing; loggers is the one that accepts a POST
and mutates state at runtime.
See the errata note above about this question's claim that info is
HTTP-exposed by default — true for Boot 2.0–2.4, not for 2.5+.
info = arbitrary, read-only app data from info.*, build-info, git.properties or an InfoContributor.dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web' // ← no version
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
The io.spring.dependency-management plugin (Gradle) or the
spring-boot-starter-parent POM (Maven) imports Boot's BOM, which pins a compatible version for
every managed dependency. That version curation is the main thing a starter buys you — not just the
grouping.
| Starter | Bundles | Does not include |
|---|---|---|
starter-web | Spring MVC, Jackson, embedded Tomcat | — |
starter-data-jpa | Spring Data JPA, Hibernate, spring-orm, HikariCP | a database driver |
starter-test | JUnit 5, Mockito, AssertJ, Hamcrest, Spring Test, JSONassert | EasyMock |
The other correct-rejection here: starter-data-jpa does not add an in-memory
database — you add H2 or Postgres yourself. Same principle as "Boot ships no vendor JDBC drivers" from
attempt #8.
86% — the best Data score of the series, four papers after its clinic.
@Transactional facts see the errata noteREQUIREDWhy interface annotations vanish under CGLIB: a CGLIB proxy is a subclass
of your class. Java does not inherit annotations from an interface onto an implementing class, and certainly not
onto a generated subclass — so Spring's attribute source never sees the interface-level
@Transactional. A JDK dynamic proxy implements the interface, so the annotation is
visible.
| Annotation placed on | JDK proxy | CGLIB proxy |
|---|---|---|
| a concrete class or its method | works | works |
| an interface or its method | works | ignored |
Spring Boot defaults to CGLIB (proxyTargetClass=true), which is why the Spring
reference documentation says: annotate concrete classes, not interfaces. This is also the safer habit
generally — it removes the proxy type from the equation entirely.
The two correct options are worth over-learning, since they're the stock @Transactional
facts: public methods only (non-public is silently ignored — no error), and default propagation
REQUIRED, default isolation DEFAULT, rollback on unchecked exceptions
only.
REQUIRES_NEW when the inner transaction failsTrace it precisely, because this is the subtlest transaction question you've had:
| Step | What happens |
|---|---|
| 1 | mainOperation() starts TX-A |
| 2 | subOperation() is REQUIRES_NEW → TX-A is suspended, TX-B starts |
| 3 | subOperation() throws → TX-B rolls back independently ✔ |
| 4 | the exception propagates into mainOperation(), which has no try/catch |
| 5 | it crosses TX-A's boundary → TX-A is marked rollback-only and rolls back too |
The one-line version: REQUIRES_NEW isolates the transactions, not the
exceptions. Independence means TX-B's rollback doesn't drag TX-A down by itself — but nothing
stops the exception travelling up the call stack in the ordinary Java way, and Spring rolls back on unchecked
exceptions by default.
@Transactional
public void mainOperation() {
try {
subService.subOperation(); // TX-B rolls back
} catch (Exception e) {
log.warn("sub failed, continuing", e); // ← now TX-A really does survive
}
}
That try/catch is the difference between the option you picked and the correct one. It's also the
real-world pattern: REQUIRES_NEW plus a catch is how you write an audit record that persists even
when the main work fails.
The distinction the question is built on is genuinely useful:
| Layer | Question it answers | Examples |
|---|---|---|
| Mechanism | How are credentials collected and transmitted? | Basic, Digest, Form, X.509, OAuth2/OIDC |
| User store | Where are the users kept? | LDAP, JDBC, in-memory |
The two layers combine: a Form login collects a username and password, and an
LdapAuthenticationProvider verifies them against an LDAP directory. Same request, two
different concerns.
This connects to a fact you already have from attempt #9: the question "where can Spring Security store user details?" has the answer JDBC, LDAP, in-memory — and LDAP is on that list precisely because it's a store, not a mechanism. The same word is the right answer to one question and the wrong answer to the other. Read which layer the stem is asking about.
@Before, @After, @AfterReturning, @AfterThrowing, @Around. @Aspect + @Component mark the classaspectjweaver required) — not SpEL; and only method-execution join points@Around = before + proceed() + after, exactly what @Transactional does internallySpelExpressionParser + StandardEvaluationContext. spring-expression needs only spring-coreBeanPostProcessor ⇒ a static @Bean method — static breaks the ordering cycle; same for BeanFactoryPostProcessorsdefault, static. Java 9 adds private. No "friend"@WebMvcTest loads the web layer — controllers, Jackson, templating, caching, MockMvc. It excludes persistence: services, repositories, DataSource, transactionsSpringExtension — @ExtendWith is redundant@Mock = an object · @MockBean = a bean definition in the context, replacing or creating onewebEnvironment = RANDOM_PORT or server.port=0. The default is MOCK — no serverMain-Class=JarLauncher, Start-Class=yoursinfo takes custom data from info.*, build-info, git.properties or an InfoContributor. It is read-onlyREQUIRED · on an interface it works with JDK proxies only, so annotate concrete classesREQUIRES_NEW isolates transactions, not exceptions — without a try/catch in the caller, both roll back@Transactional's
behaviour (Q2 and Q8 above).
(3) Then SpEL. Lesson 5 — 2 more marks, and it
overlaps with caching and security expressions.
(4) Re-drill the Boot clinic. All four Boot misses are in it, and
the fat jar has now cost you three marks across three papers.
(5) Slow back down. 35 minutes, from 42 on each of the last two papers. You have 95 minutes spare
and 10 of 18 misses were multiple ticks on one-answer questions. Target 60 minutes.
Finished: Spring MVC (100%, zero misses, after three drill rounds).
Strong: Data 86% — best of the series — and Boot 75%, both holding above their pre-clinic levels.
Recovering: Testing 60%, Security 50% off a single miss.
The work: Spring Core at 58%, holding 7 of 18 misses. It is the biggest section on the exam, it has
never been above 75%, and it is the only section without a clinic.
Three clinics have each moved their section 18–50 points and the gains have held. There is one section left, and
it happens to be the one carrying most of your remaining losses. Ask for the Spring Core clinic and you have
covered the whole syllabus.