# 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](https://ankurm.com/write-your-own-spring-boot-4-starter-auto-configuration-conditional-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/`](output). ## Layout | Module | What it is | |---|---| | [`masker-spring-boot-autoconfigure/`](masker-spring-boot-autoconfigure) | `MaskerAutoConfiguration`, `MaskerJacksonAutoConfiguration`, `MaskerProperties`, the `AutoConfiguration.imports` file, the configuration metadata, and the tests | | [`masker-spring-boot-starter/`](masker-spring-boot-starter) | The dependency an application adds. No code, only a pom | | [`masker-demo/`](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 ```bash 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`](output/01-defaults-without-any-configuration.txt) | the auto-configuration with no properties and no user beans | `MaskerAutoConfigurationTests` | | [`02`](output/02-properties-and-the-off-switch.txt) | `masker.*` properties and `masker.enabled=false` | `MaskerAutoConfigurationTests` | | [`03`](output/03-conditional-on-missing-bean-and-registration-order.txt) | `@ConditionalOnMissingBean` backing off, and the registration order that decides it | `MaskerAutoConfigurationTests` | | [`04`](output/04-jackson-integration-active.txt) | the Jackson module registered, a `Sensitive` written masked, the recorded condition outcomes | `JacksonIntegrationTests` | | [`05`](output/05-jackson-integration-absent-without-error.txt) | Jackson hidden with `FilteredClassLoader`: no failure, no module | `JacksonIntegrationTests` | | [`06`](output/06-conditional-on-bean-needs-an-ordering.txt) | `@ConditionalOnBean` with and without an ordering constraint, and the sorted order | `ConditionTrapTests` | | [`07`](output/07-conditional-on-class-on-a-bean-method.txt) | `@ConditionalOnClass` on a `@Bean` method, on a classpath with no Jackson | `capture-jar-facts.sh` | | [`08`](output/08-auto-configuration-missing-from-the-imports-file.txt) | an auto-configuration missing from the imports file: passes a runner test, absent everywhere | `ForgottenImportsEntryTests` | | [`09`](output/09-reading-the-imports-file-in-a-test.txt) | `ImportCandidates`, the guard test for the omission | `ForgottenImportsEntryTests` | | [`10`](output/10-demo-app-with-only-the-starter.txt) | an application with only the starter dependency, and Boot's recorded conditions | `DemoApplicationTests` | | [`11`](output/11-demo-app-properties-and-off-switch.txt) | the same application with properties, then switched off | `DemoApplicationTests` | | [`12`](output/12-jar-contents-and-dependency-trees.txt) | what is in the two jars, and what the starter pulls in | `capture-jar-facts.sh` | | [`13`](output/13-configuration-metadata-in-the-jar.txt) | the generated and the hand-written configuration metadata, and the auto-configuration conditions metadata | `capture-jar-facts.sh` | | [`14`](output/14-boot4-autoconfiguration-locations.txt) | Boot 4's split of `spring-boot-autoconfigure`, and the Boot 3 import that no longer compiles | `capture-jar-facts.sh` | | [`15`](output/15-annotation-processor-version-trap.txt) | the processor path failing when the version is taken from your own parent | `capture-jar-facts.sh` | | [`17`](output/17-where-the-classes-live.txt) | which Boot 4.1.1 jar holds each class this starter imports | `capture-jar-facts.sh` | | [`16`](output/16-conditional-on-property-without-match-if-missing.txt) | `@ConditionalOnProperty` without `matchIfMissing` | `ConditionTrapTests` | Transcripts are deterministic; only build-directory paths are rewritten, to ``.