Two-jar starter (autoconfigure + starter), a demo app, and 17 captured transcripts covering AutoConfiguration.imports, @ConditionalOn*, ordering, optional Jackson 3 integration, configuration metadata and the Boot 4 module split. Co-Authored-By: Claude Sonnet 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01Uu7q8vPeREyT4218EJPzz1
custom-starter
A Spring Boot 4 starter written from scratch, and the application that uses it. Companion to Write Your Own Spring Boot 4 Starter: Auto-Configuration, @Conditional and Properties.
The starter provides one thing, a Masker that hides all but the last few characters of a value, plus an optional
Jackson integration that writes a Sensitive value masked. The subject is the packaging, not the masking.
| Spring Boot | 4.1.1 (parent pom, published 20 Aug 2026) |
| Spring Framework | 7.0.9 |
| Java | 25 |
| Maven | 3.9 |
There is no docs/ folder. The explanations live in the article, in collapsible sections next to the paragraph
each one extends, and every console block in the article is quoted from a file in output/.
Layout
| Module | What it is |
|---|---|
masker-spring-boot-autoconfigure/ |
MaskerAutoConfiguration, MaskerJacksonAutoConfiguration, MaskerProperties, the AutoConfiguration.imports file, the configuration metadata, and the tests |
masker-spring-boot-starter/ |
The dependency an application adds. No code, only a pom |
masker-demo/ |
An application that adds the starter and nothing else |
masker-spring-boot-autoconfigure/src/test/java/com/ankurm/traps/ holds auto-configurations that are wrong on
purpose. src/broken/ holds a source file that is made not to compile on purpose. Neither is part of the shipped jar.
Run it
export JAVA_HOME=/path/to/jdk-25
./scripts/run-all.sh # tests, then the jar and failure captures: regenerates all of output/
mvn -B test # only the tests
Captured output
| File | What it shows | Made by |
|---|---|---|
01 |
the auto-configuration with no properties and no user beans | MaskerAutoConfigurationTests |
02 |
masker.* properties and masker.enabled=false |
MaskerAutoConfigurationTests |
03 |
@ConditionalOnMissingBean backing off, and the registration order that decides it |
MaskerAutoConfigurationTests |
04 |
the Jackson module registered, a Sensitive written masked, the recorded condition outcomes |
JacksonIntegrationTests |
05 |
Jackson hidden with FilteredClassLoader: no failure, no module |
JacksonIntegrationTests |
06 |
@ConditionalOnBean with and without an ordering constraint, and the sorted order |
ConditionTrapTests |
07 |
@ConditionalOnClass on a @Bean method, on a classpath with no Jackson |
capture-jar-facts.sh |
08 |
an auto-configuration missing from the imports file: passes a runner test, absent everywhere | ForgottenImportsEntryTests |
09 |
ImportCandidates, the guard test for the omission |
ForgottenImportsEntryTests |
10 |
an application with only the starter dependency, and Boot's recorded conditions | DemoApplicationTests |
11 |
the same application with properties, then switched off | DemoApplicationTests |
12 |
what is in the two jars, and what the starter pulls in | capture-jar-facts.sh |
13 |
the generated and the hand-written configuration metadata, and the auto-configuration conditions metadata | capture-jar-facts.sh |
14 |
Boot 4's split of spring-boot-autoconfigure, and the Boot 3 import that no longer compiles |
capture-jar-facts.sh |
15 |
the processor path failing when the version is taken from your own parent | capture-jar-facts.sh |
17 |
which Boot 4.1.1 jar holds each class this starter imports | capture-jar-facts.sh |
16 |
@ConditionalOnProperty without matchIfMissing |
ConditionTrapTests |
Transcripts are deterministic; only build-directory paths are rewritten, to <custom-starter>.