Add custom-validation, etag-caching, restclient-basic-auth: Boot 4.1 API pass

Three companion modules verifying and rewriting the Boot 4.1.1 / Framework
7.0.9 story for three older articles: the javax->jakarta.validation namespace
fix plus Jakarta Validation 3.1 record-validation clarification, ETag/
conditional-request APIs re-verified unchanged plus the starter rename, and
RestTemplate Basic Auth rebuilt on RestClient with the exchange() trap called
out. 19 real passing tests generate every transcript quoted from the three
companion articles.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01EQNA6DJ9VgCtW6zhCE8Xud
This commit is contained in:
Claude
2026-09-19 10:17:09 +00:00
parent 03bdf7ee87
commit e4b5636f7c
75 changed files with 2374 additions and 0 deletions
+66
View File
@@ -0,0 +1,66 @@
# custom-validation
Companion module for [**Custom Validation in Spring Boot: Beyond the Basics!**](https://ankurm.com/custom-validation-in-spring-boot-beyond-the-basics/)
on ankurm.com, rewritten around **Jakarta Validation 3.1** (Spring Boot 4.1.1 / Hibernate Validator
9.1.3.Final) and the `jakarta.validation` namespace the original article's `javax.validation` code
never actually ran under on Boot 3+.
`mvn test` regenerates every transcript in [`docs/output/`](docs/output) -- the test suite is the
transcript generator.
## Versions
| | |
|---|---|
| Spring Boot | 4.1.1 |
| Spring Framework | 7.0.9 |
| Hibernate Validator | 9.1.3.Final (`jakarta.validation-api` 3.1.1) -- confirmed with `mvn dependency:tree` and by reading the jars' own manifests, see [docs/01](docs/01-jakarta-namespace-and-bean-validation-3-1.md) |
| JDK | Eclipse Temurin 25.0.4.1 (LTS) |
## Quickstart
```bash
export JAVA_HOME=/path/to/jdk-25
mvn -DskipTests package
./scripts/run.sh # port 8080
curl -s -X POST localhost:8080/contact -H 'Content-Type: application/json' \
-d '{"email":"[email protected]","message":"hello there, this message is long enough"}'
mvn test # 10 tests, regenerates docs/output/
```
## Endpoints
| Endpoint | Shows |
|---|---|
| `POST /contact` | field-level custom constraint (`@SpamMessageCheck`), class-based DTO, `BindingResult` |
| `POST /contact-record` | the same constraint on a record component |
| `POST /booking` | class-level (cross-field) custom constraint (`@DateRangeValid`), class-based DTO |
| `POST /booking-record` | the same cross-field constraint on a record's type declaration |
| `GET /diagnostic/validation-provider` | prints the real Bean Validation provider and spec version at runtime -- delete before shipping |
## Documentation
1. [The jakarta.validation namespace, and what Bean Validation 3.1 actually changed](docs/01-jakarta-namespace-and-bean-validation-3-1.md)
2. [Record validation, field-level and class-level](docs/02-record-validation.md)
3. [What the defaults do not do: record validation failures with no error body](docs/03-what-the-defaults-do-not-do.md)
## Findings worth the trip
- **The original article's `javax.validation.*` imports never worked on Spring Boot 3+.** Boot 3
moved entirely to the `jakarta.*` namespace in December 2022; this module is the corrected,
runnable version.
- **Spring Boot 4.1.1 pins Hibernate Validator 9.1.3.Final / Jakarta Validation 3.1**, confirmed
by `mvn dependency:tree` and independently by reading the actual jar manifests at test time.
- **A record validation failure with no `BindingResult` in the controller signature returns an
EMPTY 400 body by default** -- not a JSON error, not even with `Accept: application/json`.
- **`spring.mvc.problemdetails.enabled=true` fixes the empty body but not the missing detail**:
the resulting `ProblemDetail` is generic (`"Invalid request content."`), with no per-field
messages, unless you write a custom `@ExceptionHandler` to put them there yourself.
- **`AutoConfigureMockMvc` moved packages in Boot 4.1**, from
`org.springframework.boot.test.autoconfigure.web.servlet` to
`org.springframework.boot.webmvc.test.autoconfigure` -- and `spring-boot-starter-test` alone no
longer pulls in MockMvc's autoconfiguration; that needs `spring-boot-starter-webmvc-test`.
## License
MIT -- see [LICENSE](../LICENSE).