From 879a06929ab68d9c87e9460c90efbcc36b65f1d0 Mon Sep 17 00:00:00 2001 From: asmhatre Date: Sat, 25 Jul 2026 08:21:13 +0000 Subject: [PATCH] README: document the 4-article series and the corner-scenarios enrichment --- README.md | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 124116d..6b35f97 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,35 @@ # sdjpa4-demo -Runnable companion project for [Spring Data JPA 3 to 4 Migration Guide](https://ankurm.com/spring-data-jpa-3-to-4-migration-guide-2/) on ankurm.com. +Runnable companion project for the Spring Data JPA 3 to 4 migration series on ankurm.com: -Four entities, two repositories, a `@NullMarked` package, seven passing behavior tests, and an A-G demo runner that prints every labelled console output shown in the article. Boots H2 in memory, so there's nothing to install beyond a JDK. +- [Spring Data JPA 3 to 4 Migration Guide](https://ankurm.com/spring-data-jpa-3-to-4-migration-guide/) (overview, start here) +- [Migration Baseline](https://ankurm.com/spring-data-jpa-3-to-4-migration-guide-2/) +- [Query Engine Rewrite: Criteria to JPQL](https://ankurm.com/spring-data-jpa-4-derived-queries-criteria-to-jpql/) +- [Advanced Migration: Specifications, AOT, EntityManager](https://ankurm.com/spring-data-jpa-4-specifications-aot-entitymanager/) -Built and verified on Eclipse Temurin JDK 21.0.11, Spring Boot 4.0.6, Spring Data JPA 4.0.6, Hibernate ORM 7.2, H2 in-memory. +Four entities, three repositories, a `@NullMarked` package, 20 passing behavior tests, and an A-L demo runner that prints every labelled console output shown in the articles. Boots H2 in memory, so there's nothing to install beyond a JDK. + +Built and verified on Eclipse Temurin JDK 21, Spring Boot 4.0.6, Spring Data JPA 4.0.6, Hibernate ORM 7.2, H2 in-memory. ## Run it ``` git clone https://ankurm.com/git.app/asmhatre/sdjpa4-demo.git cd sdjpa4-demo -./mvnw spring-boot:run # prints the labelled A-G demonstrations -./mvnw test # runs the 7 behavior tests (all green) +./mvnw spring-boot:run # prints the labelled A-L demonstrations +./mvnw test # runs the 20 behavior tests (all green) ``` + +## Tags + +- `article-1-baseline`, `article-2-query-engine`, `article-3-advanced` - the exact code each article quotes, frozen at publish time. +- `corner-scenarios` (and `main`) - the enriched, current state described below. Some method signatures have moved on from the article-tagged snapshots (e.g. `Book`'s `price` is now an embedded `Money` value object, not a bare `BigDecimal`), so check out the matching article tag if you want the code to line up exactly with what's quoted in a given post. + +## What's covered beyond the three articles (corner-scenario enrichment) + +- **Refined Specification API** (`AuthorSpecifications.java`): `PredicateSpecification` reused across a read and a bulk delete, an explicit `DeleteSpecification` (`CriteriaDelete`-backed), and an `UpdateSpecification` (`CriteriaUpdate`-backed bulk update composed from an `UpdateOperation` + a `where(...)` predicate). +- **`JpaSort.unsafe(...)` with a `CASE` expression** - a real `ORDER BY case when country = 'US' then 0 else 1 end` sort combined with a plain derived query. +- **`Money`, an `@Embeddable` record value object** on `Book.price`, with derived queries that traverse the embedded path (`findByPriceAmountGreaterThanEqual`, `findByPriceAmount`). +- **A genuine corner case, found by actually running it**: a derived-query class-based (record) projection resolves constructor-parameter names against *direct* entity properties only. `BookSummary(String title, BigDecimal amount)` does **not** resolve `amount` against the nested `price.amount` path via a plain `findBy...` derived method - it throws `PropertyReferenceException: No property 'amount' found for type 'Book'`. The fix is an explicit `@Query` constructor expression (`select new ...BookSummary(b.title, b.price.amount) from Book b where ...`), which does work for nested/embedded paths. See `BookRepository.findByPriceAmountLessThanEqual`. + +All of the above is exercised by both the demo runner (`DemoRunner.java`, sections H-L) and dedicated tests in `MigrationBehaviorTests.java`.