Three new article modules: configuration binding, profiles and config data, Spring AOP
configuration-properties/ @ConfigurationProperties vs @Value on Spring Boot 4.1.1. The relaxed-binding matrix is generated by binding each spelling rather than transcribed, and re-checked against real processes -- the in-process probe was wrong twice before it was right. Records the three findings that came out of it: @Value does get relaxed resolution inside Spring Boot (Boot attaches ConfigurationPropertySources), the configuration processor silently stops generating metadata on JDK 23+ when declared as a plain dependency, and @Valid is not what makes nested constraints run. profiles-and-config/ Precedence, profiles, spring.config.import and config trees. /precedence reports every source holding a property in rank order with file and line, which turns "my profile file had no effect" into a two-line answer. Also pins the counterintuitive one: an imported file outranks the file that imported it. spring-aop/ Designators, proxy types, and aspects that do not fire. One advice per supported designator so the reference table is generated from real matches; all fourteen unsupported designators fed to the parser. Two corrections to the reference documentation: unsupported designators throw UnsupportedPointcutPrimitiveException (extends RuntimeException, not IllegalArgumentException), and spring-boot-starter-aop was renamed to spring-boot-starter-aspectj in Boot 4. 19 contract tests across the three modules, 15 captured transcripts, all regenerated by scripts/run-all.sh. Verified on Spring Boot 4.1.1, Spring Framework 7.0.9, JDK 25.0.4.1. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Gip4srpzMwjgoba6uEfbr5
This commit is contained in:
55
configuration-properties/docs/05-validation.md
Normal file
55
configuration-properties/docs/05-validation.md
Normal file
@@ -0,0 +1,55 @@
|
||||
[← Records and defaults](04-records-and-defaults.md) · [Index](../README.md) · [When @Value wins →](06-when-value-still-wins.md)
|
||||
|
||||
# 5. Validation
|
||||
|
||||
Transcript: [`04-validation-failure.txt`](output/04-validation-failure.txt).
|
||||
Type: [`ValidatedProperties`](../src/main/java/com/ankurm/configprops/props/ValidatedProperties.java).
|
||||
|
||||
This is the capability `@Value` does not have at all, and the reason to prefer binding for
|
||||
anything that can be misconfigured.
|
||||
|
||||
## What it takes
|
||||
|
||||
1. `spring-boot-starter-validation` on the classpath. Without a validator implementation,
|
||||
`@Validated` is a no-op — nothing is checked and nothing says so.
|
||||
2. `@Validated` on the properties type.
|
||||
3. JSR-380 constraints on the components.
|
||||
|
||||
## What you get
|
||||
|
||||
A bad value becomes a startup failure that names the property, the offending value, the file
|
||||
and line it came from, and the constraint it broke — all of them at once, not one per restart:
|
||||
|
||||
```
|
||||
Property: demo.validated.port
|
||||
Value: "99999"
|
||||
Origin: class path resource [application-badvalidation.yaml] - 6:11
|
||||
Reason: must be less than or equal to 65535
|
||||
```
|
||||
|
||||
The alternative is a `NumberFormatException` in a request handler at 3am.
|
||||
|
||||
## `@Valid` on nested types is not what makes them validate
|
||||
|
||||
The rule "annotate nested properties with `@Valid` or their constraints are ignored" is widely
|
||||
repeated and does not apply here. It is true of ordinary bean validation, where cascading is
|
||||
opt-in. Spring Boot's `ValidationBindHandler` validates *every object the binder finishes
|
||||
constructing*, nested ones included.
|
||||
|
||||
`BindingContractTests.nestedConstraintsFireWithoutValid` pins this: a nested record carrying
|
||||
`@Max(100)` and no `@Valid` anywhere in the type still fails the bind at 4000. That test was
|
||||
originally written to assert the opposite and failed, which is how it ended up documented here.
|
||||
|
||||
Keep writing `@Valid` if you like — it is harmless and it is what a reader expects. Just do not
|
||||
believe it is load-bearing.
|
||||
|
||||
## Ordering
|
||||
|
||||
The violation order in the failure report is not stable between runs. Do not write a test that
|
||||
asserts on it.
|
||||
|
||||
## Custom validation
|
||||
|
||||
For rules a constraint annotation cannot express — "if `mode` is `remote` then `endpoint` is
|
||||
required" — implement `Validator` and expose it as a bean named `configurationPropertiesValidator`.
|
||||
It runs at bind time with the same reporting.
|
||||
Reference in New Issue
Block a user