0Pricing
Java Academy · Lesson

Pagination, Sorting, and Projections

Return paged results with Pageable, sort dynamically, and use interface projections to limit fetched columns.

Pagination, Sorting, and Projections is a free Java Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Java Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Why Pagination?

Returning thousands of rows in one query wastes memory and bandwidth. Pagination loads one page at a time. Spring Data integrates pagination with the Pageable abstraction.

Pageable and PageRequest

Create a Pageable using PageRequest.of(page, size). Pass it to any repository method that returns Page<T>.

Pageable pageable = PageRequest.of(0, 20); // page 0, 20 per page
Page<User> page = userRepo.findAll(pageable);
System.out.println("Total: " + page.getTotalElements());
System.out.println("Pages: " + page.getTotalPages());
System.out.println("Content: " + page.getContent().size());

Sort with PageRequest

Add sorting to PageRequest with a Sort object. Chain multiple fields with Sort.by().and().

Pageable sorted = PageRequest.of(0, 20,
    Sort.by(Sort.Direction.DESC, "createdAt")
        .and(Sort.by("name")));
Page<User> page = userRepo.findAll(sorted);

Slice vs Page

Page<T> fires a COUNT query to compute total pages. Slice<T> does not — it only knows if there is a next page. Use Slice for infinite scroll where total count is not needed.

public interface UserRepository extends JpaRepository<User, Long> {
    Slice<User> findByStatus(UserStatus status, Pageable pageable);
}

Spring MVC Integration

Spring MVC auto-resolves Pageable from query parameters: ?page=0&size=20&sort=name,asc. No manual parsing needed.

@GetMapping("/users")
public Page<UserDto> list(Pageable pageable) {
    return userRepo.findAll(pageable).map(UserDto::from);
}
// GET /users?page=0&size=10&sort=name,asc

Interface Projections

Define an interface with getter methods matching entity field names. Spring Data returns only those columns — reducing data transfer and hiding internals.

public interface UserSummary {
    Long getId();
    String getName();
    String getEmail();
}
List<UserSummary> findByStatus(UserStatus status);

Class-Based (DTO) Projections

Use a DTO record or class with a constructor. Spring Data generates a JPQL constructor expression for the selected columns.

public record UserDto(Long id, String name, String email) {}

@Query("SELECT new com.example.UserDto(u.id, u.name, u.email) FROM User u WHERE u.status = :s")
List<UserDto> findSummaries(@Param("s") UserStatus status);

Dynamic Projections

Pass the projection type as a generic parameter to the repository method to choose the projection at the call site.

public interface UserRepository extends JpaRepository<User, Long> {
    <T> List<T> findByStatus(UserStatus status, Class<T> type);
}
// Usage:
List<UserSummary> summaries = repo.findByStatus(ACTIVE, UserSummary.class);
List<User>        full      = repo.findByStatus(ACTIVE, User.class);

Keyset Pagination (Offset vs Keyset)

Offset pagination (OFFSET N) degrades at large offsets. Keyset pagination (using WHERE id > lastSeenId) is O(1) regardless of page depth — better for deep pagination.

// Keyset pagination:
@Query("SELECT u FROM User u WHERE u.id > :lastId ORDER BY u.id LIMIT :size")
List<User> findPage(@Param("lastId") Long lastId, @Param("size") int size);

Total Count Optimization

Use countQuery in @Query to provide an optimized count query that avoids expensive JOINs on the main query.

@Query(value = "SELECT u FROM User u JOIN FETCH u.orders WHERE u.status = :s",
       countQuery = "SELECT COUNT(u) FROM User u WHERE u.status = :s")
Page<User> findActiveWithOrders(@Param("s") UserStatus s, Pageable p);

Returning ResponseEntity with Page Metadata

Include page metadata (totalElements, totalPages, number, size) in the REST response so clients know how to navigate.

@GetMapping("/users")
public ResponseEntity<Map<String, Object>> list(Pageable p) {
    Page<UserDto> page = repo.findAll(p).map(UserDto::from);
    return ResponseEntity.ok(Map.of(
        "content", page.getContent(),
        "totalElements", page.getTotalElements(),
        "totalPages", page.getTotalPages()
    ));
}

Quick Check

What is the key difference between Page and Slice?

Recap

Use Pageable+PageRequest.of() for offset pagination. Spring MVC resolves Pageable from query params. Use Slice to avoid COUNT. Use interface or DTO projections to limit fetched columns. Keyset pagination for large offsets.

Frequently asked questions

Is the “Pagination, Sorting, and Projections” lesson free?

Yes — the full text of “Pagination, Sorting, and Projections” is free to read here on the web, and the Java Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Java Academy course, upgrade to CoddyKit PRO.

What will I learn in “Pagination, Sorting, and Projections”?

Return paged results with Pageable, sort dynamically, and use interface projections to limit fetched columns. You practise Java Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start Java Academy?

No prior experience is required. Java Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Pagination, Sorting, and Projections” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this Java Academy lesson?

Yes. Every Java Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Entity Mapping with JPA Annotations
  2. Spring Data Repositories and Query Methods
  3. One-to-Many and Many-to-Many Relationships
  4. Pagination, Sorting, and Projections
← Back to Java Academy