Foundation · Build
Projections, Specifications & Auditing
Build efficient read models, compose optional search filters, and capture creation/update timestamps without exposing managed entities.
Primary source: Spring Data JPA: Projections and DTO Read Models
Lesson 16 of 17
1d streakThe Architectural Question
Loading full entity graphs for list screens wastes memory and couples API responses to the persistence model, while ad-hoc string query combinations become impossible to maintain.
What this guide proves
- DTO Projections
- JpaSpecificationExecutor
- JPA Auditing
Read models: Decoupling query views from write entities
Using JPA entities for read-heavy operations is a performance hazard: entities attach to the Persistence Context, consume heap memory, and trigger dirty checking comparisons. Read models decouple queries into lightweight DTOs and database views.
| Dimension | Write Model (JPA Entity) | Read Model (Projection / DTO) |
|---|---|---|
| State | Managed, mutable, attached to L1 cache | Detached, immutable Java Record |
| Dirty Checking | Yes (generates diff snapshots) | No (zero dirty checking overhead) |
| Associations | Complex object graphs, proxy references | Flattened tabular projections |
| Security | May accidentally expose internal columns | Exposes strictly the requested public fields |
Interface-based vs Class-based DTO projections
// Fast class-based Record Projection
public record OrderSummaryView(UUID id, String customerEmail, double total) {}
public interface OrderRepository extends JpaRepository<OrderEntity, UUID> {
@Query("SELECT new com.example.orders.dto.OrderSummaryView(o.id, o.customerEmail, o.totalAmount) FROM OrderEntity o WHERE o.status = :status")
List<OrderSummaryView> findSummariesByStatus(String status);
}Active Recall Checkpoint
Why are Java 21 Record DTO projections preferred over dynamic interface-based projections in high-throughput endpoints?
Hint: Consider JDK dynamic proxy overhead.
Show answer & explanation
Spring Data implements interface projections using JDK dynamic proxies, which incurs small runtime reflection overhead per row. Java Record DTOs are instantiated directly by the query without proxy overhead.
Read model guidelines
Use it when
Use constructor DTO projections or database views for all search, dashboard, and listing endpoints.
Reconsider when
Load full JPA entities only when mutating business state that must be saved back to the database.
Runtime Architecture & Flow
Decision canvas
Evaluate the choice across three constraints
These are comparison criteria, not sequential steps. A strong answer states which constraint dominates in the current system.
DTO Projections
Ask how each option changes this guarantee, its operational cost, and its failure mode.
JpaSpecificationExecutor
Ask how each option changes this guarantee, its operational cost, and its failure mode.
JPA Auditing
Ask how each option changes this guarantee, its operational cost, and its failure mode.
Decision prompt: Add a lightweight `ProductSummary` projection, a composable catalog search specification, and created/updated timestamps to the product catalog.
Synthesis & Production Verification
Deliberate Failure Condition
- Break: Return a Page<Product> directly from the controller and serialize a lazy relationship
- Observe: Unplanned SQL, unstable JSON, or LazyInitializationException
- Repair: Select the response shape deliberately and map it inside the transaction instead of treating entities as API DTOs.
Production Acceptance Criteria
- Return a projection containing only list-screen fields
- Compose optional filters without one repository method per combination
- Populate audit timestamps automatically
Key Takeaway
Decouple read models from JPA write entities using lightweight constructor DTO projections to bypass dirty checking and memory bloat.
Architectural & Technical Review
Core Interview Questions
Q01Why should read-only endpoints avoid loading managed JPA entities?Show answer
Managed entities consume heap for snapshot tracking and dirty checking comparisons; DTO records are lightweight and immutable.
Q02What is the benefit of constructor DTO projections over interface projections?Show answer
Constructor projections instantiate concrete record instances directly, bypassing JDK dynamic proxy overhead per row.
Q03How do read models improve API security?Show answer
They expose strictly the requested fields, preventing accidental serialization of sensitive entity attributes.
Production Pitfalls
Critical Anti-Patterns
- Pitfall: Serializing managed entities directly to JSON clients — Exposing entities leaks internal database columns and triggers LazyInitializationExceptions when touching uninitialized proxies.
- Pitfall: Creating interface projections with heavy computed getters — SpEL expressions in interface projection getters execute per row in memory, slowing down pagination results.
Primary Documentation & Specifications
Lesson Primary References
Supplementary Module Resources