Files
Claude c418589251 Add custom-starter module: a Boot 4 auto-configuration starter with conditions, metadata and runner tests
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
2026-09-24 06:53:07 +00:00

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>`.