[← 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.