Skip to content
Development
Skill

/java-jpa

Reviews Spring Data JPA for N+1 queries, fetch strategies, projections, and Specifications. Use when user asks to "review JPA", "check for N+1", "JPA performance", "review my entities", "check fetch strategy", or "review my repositories".

From plugin
claude-java-plugins
1726 skills6 agents5 commands

Claude Code

$ npx -y skills add ducpm2303/claude-java-plugins --skill java-jpa --agent claude-code

SKILL.md

java-jpa.SKILL.md
description: Reviews Spring Data JPA for N+1 queries, fetch strategies, projections, and Specifications. Use when user asks to "review JPA", "check for N+1", "JPA performance", "review my entities", "check fetch strategy", or "review my repositories".
argument-hint: "[file or class to review, optional]"

/java-jpa โ€” Spring Data JPA Deep Review

You are a Spring Data JPA specialist. Review JPA code for common performance and correctness problems.

Step 1 โ€” Detect Java and Spring Boot version

Check `pom.xml` or `build.gradle` for:

  • Java version (affects stream/record usage)
  • Spring Boot version (2.x uses `javax.persistence.*`, 3.x uses `jakarta.persistence.*`)

If neither is found, ask the user.

Step 2 โ€” Identify scope

If the user provided a file or class name, focus on that. Otherwise, scan for:

  • `@Entity`, `@Repository`, `@Service` classes
  • `JpaRepository` / `CrudRepository` / `PagingAndSortingRepository` extensions
  • JPQL and native queries (`@Query`)
  • `@Transactional` annotations

Step 3 โ€” Review for these issues

N+1 Query Detection (HIGH PRIORITY)

Look for:

  • `@OneToMany` or `@ManyToMany` without `fetch = FetchType.LAZY` (lazy is required; eager causes N+1 on collections)
  • Loops that call a repository method or access a lazy collection on each iteration
  • Missing `@EntityGraph` or JOIN FETCH when a relationship is always needed together

For each N+1 found, show:

โš ๏ธ  N+1 DETECTED: UserService.getUsersWithOrders()
    Problem: orders collection loaded lazily inside a loop (line 42)
    Fix:
      Option A โ€” @EntityGraph on the repository method:
        @EntityGraph(attributePaths = {"orders"})
        List<User> findAll();

      Option B โ€” JOIN FETCH in JPQL:
        @Query("SELECT u FROM User u JOIN FETCH u.orders")
        List<User> findAllWithOrders();

Fetch Strategy Review

  • Flag `FetchType.EAGER` on `@OneToMany` / `@ManyToMany` โ€” always wrong
  • Flag missing `@BatchSize` when lazy collections will be accessed in loops
  • Suggest `@EntityGraph` for use-case-specific eager loading without global EAGER

Projection Usage

Check if entities are returned where only a subset of fields is needed:

๐Ÿ’ก  PROJECTION OPPORTUNITY: UserRepository.findAllForList()
    Returns full User entity but only id, name, email are used in UserListDto.
    Fix: Use an interface projection or record projection (Java 16+):

    // Interface projection (Java 8+)
    public interface UserSummary {
        Long getId();
        String getName();
        String getEmail();
    }
    List<UserSummary> findAllBy();

    // Record projection (Java 16+, Spring Boot 2.6+)
    public record UserSummary(Long id, String name, String email) {}
    @Query("SELECT new com.example.UserSummary(u.id, u.name, u.email) FROM User u")
    List<UserSummary> findAllSummaries();

Specification / Criteria API

If dynamic queries are constructed with string concatenation or if/else JPQL building:

๐Ÿ’ก  SPECIFICATION OPPORTUNITY: ProductRepository
    Dynamic query built with string concatenation is brittle and not type-safe.
    Fix: Use JpaSpecificationExecutor<Product> + Specification<Product>:

    public static Specification<Product> hasCategory(String category) {
        return (root, query, cb) ->
            category == null ? null : cb.equal(root.get("category"), category);
    }
    public static Specification<Product> priceBetween(BigDecimal min, BigDecimal max) {
        return (root, query, cb) ->
            cb.between(root.get("price"), min, max);
    }
    // Usage:
    repo.findAll(hasCategory(cat).and(priceBetween(min, max)));

Transaction Boundaries

  • Flag `@Transactional` on controller methods โ€” belongs at service layer only
  • Flag `@Transactional(readOnly = true)` missing on read-only service methods (enables Hibernate optimizations)
  • Flag calling a `@Transactional` method from within the same bean (self-invocation bypasses proxy)
  • Flag long transactions that include external HTTP calls or file I/O

Entity Design

  • Flag mutable `List`/`Set` fields without `@Column(nullable = false)` / proper constraints
  • Flag missing `equals()` and `hashCode()` on entities used in Sets or as Map keys
  • Flag `@GeneratedValue(strategy = GenerationType.AUTO)` โ€” prefer `IDENTITY` (MySQL/PostgreSQL) or `SEQUENCE` for performance
  • Flag bidirectional relationships without the owning side's `mappedBy` set correctly

Pagination

  • Flag `findAll()` without `Pageable` when the table could be large
  • Suggest `Page<T>` vs `Slice<T>` (use Slice when total count is not needed โ€” avoids COUNT query)

Native Queries

  • Flag native `@Query` with `nativeQuery = true` when JPQL would suffice
  • Flag string-interpolated table/column names in native queries (SQL injection risk)

Step 4 โ€” Output

Produce a structured report:

## JPA Review โ€” [ClassName or scope]

### Critical Issues
[N+1 problems, missing transactions on writes]

### Performance Improvements
[Fetch strategies, projections, pagination]

### Design Suggestions
[Entity design, Specifications, equals/hashCode]

### Minor Notes
[readOnly transactions, GenerationType, etc.]

### Summary
X critical ยท Y performance ยท Z design ยท W minor

For each issue include: what was found, why it matters, and the exact fix with code.

Step 5 โ€” Next Steps

After the report, offer:

  • *"Run `/java-performance` for a broader performance review including non-JPA issues"*
  • *"Use the `java-performance-reviewer` agent for an in-depth performance analysis"*
  • *"Run `/java-review` for general code quality review"*
Read more
@ducpm2303
Ships withclaude-java-plugins

A Claude Code plugin marketplace with 3 focused plugins for Java developers. All plugins support Java 8 through Java 21 and tailor advice to your target Java version.

1726 skills6 agents
Get the whole plugin

Stars on GitHub

Momentum

stars in total
17
Star history of ducpm2303/claude-java-plugins on GitHub, a chart by star-history.com

Other skills on claude-java-plugins.

java-adr

java-adr

Creates, lists, and manages Architecture Decision Records for Java projects. Use when user asks to "create an ADR", "documentโ€ฆ

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, orโ€ฆ

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills2w309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android โ€” semantic ARIA roles and labels,โ€ฆ

ecc2w293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commitsโ€ฆ

react5d252k
@facebook@facebookInstall Skill

Questions about java-jpa.

Which coding agents can use java-jpa?
java-jpa installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.