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
61 lines
4.7 KiB
Markdown
61 lines
4.7 KiB
Markdown
# 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 `<custom-starter>`.
|