java
41 lines · 7 steps
Projection interfaces in Spring Data JPA
A repository maps a grouped revenue query straight onto a typed interface, computed fields and all.
Explained by
highlit
1package com.example.orders.repository;
2
3import com.example.orders.domain.Order;
4import org.springframework.data.jpa.repository.JpaRepository;
5import org.springframework.data.jpa.repository.Query;
6import org.springframework.data.repository.query.Param;
7
8import java.math.BigDecimal;
9import java.time.Instant;
10import java.util.List;
11
12public interface OrderRepository extends JpaRepository<Order, Long> {
13
14 interface CustomerRevenue {
15 Long getCustomerId();
16 String getCustomerName();
17 long getOrderCount();
18 BigDecimal getTotalRevenue();
19
20 default boolean isHighValue() {
21 return getTotalRevenue().compareTo(new BigDecimal("1000")) >= 0;
22 }
23 }
24
25 @Query("""
26 select c.id as customerId,
27 c.name as customerName,
28 count(o) as orderCount,
29 coalesce(sum(o.total), 0) as totalRevenue
30 from Order o
31 join o.customer c
32 where o.placedAt >= :since
33 and o.status = com.example.orders.domain.OrderStatus.COMPLETED
34 group by c.id, c.name
35 having sum(o.total) > :threshold
36 order by sum(o.total) desc
37 """)
38 List<CustomerRevenue> findRevenueByCustomerSince(
39 @Param("since") Instant since,
40 @Param("threshold") BigDecimal threshold);
41}
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Interface projections let Spring Data return exactly the columns a query selects, without a dedicated entity or DTO class.
- 2JPQL aliases must match projection getter names so Spring can bind each selected value to the right accessor.
- 3Default methods on a projection interface add derived logic that lives with the data rather than in calling code.
Related explainers
java
public class SlidingLogRateLimiter { private final int maxRequests; private final long windowMillis;
How a sliding-log rate limiter works
rate-limiting
concurrency
sliding-window
Advanced
8 steps
java
public final class Slugifier { private static final Pattern NON_LATIN = Pattern.compile("[^\\w-]"); private static final Pattern WHITESPACE = Pattern.compile("[\\s]+");
Building a URL slugifier in Java
regex
unicode-normalization
string-processing
Intermediate
8 steps
java
@Repository public interface OrderRepository extends JpaRepository<Order, Long> { @Query("""
Keyset pagination with Spring Data JPA
pagination
cursor
jpa
Advanced
8 steps
java
public record FixedWidthField(String name, int start, int end) { public String extract(String line) { int from = Math.min(start, line.length());
Parsing fixed-width text in Java
records
parsing
streams
Intermediate
7 steps
java
@RestController @RequestMapping("/api/quotes") public class QuoteStreamController {
Streaming market quotes with Spring WebFlux
reactive-streams
backpressure
server-sent-events
Advanced
9 steps
java
@Controller public class BookController { private final BookService bookService;
Solving GraphQL N+1 with batch mapping in Spring
graphql
n+1-problem
batching
Intermediate
8 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/projection-interfaces-in-spring-data-jpa-explained-java-e484/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.