Spring Data JPA
JpaRepository
Repository Annotation
Spring Framework
Java Persistence API

Repository not necessary when implementing JpaRepository?

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

When you create an interface that extends JpaRepository, you do not need to add the @Repository annotation. Spring Data JPA automatically detects interfaces that extend its repository base interfaces (Repository, CrudRepository, JpaRepository) and creates proxy implementations at startup. The @Repository annotation is technically redundant because SimpleJpaRepository — the default implementation Spring generates — is already annotated with @Repository internally.

Why @Repository Is Not Needed

java
1// This is sufficient — no @Repository needed
2public interface UserRepository extends JpaRepository<User, Long> {
3    List<User> findByEmail(String email);
4}

Spring Boot auto-configuration scans for interfaces extending JpaRepository through @EnableJpaRepositories, which is included automatically via @SpringBootApplication. The scanning mechanism does not rely on @Repository — it looks for the JpaRepository (or CrudRepository, Repository) type hierarchy.

How Spring Detects Repositories

java
1// @SpringBootApplication includes @EnableAutoConfiguration
2// which triggers JpaRepositoriesAutoConfiguration
3// which triggers @EnableJpaRepositories
4
5@SpringBootApplication
6public class MyApplication {
7    public static void main(String[] args) {
8        SpringApplication.run(MyApplication.class, args);
9    }
10}
11
12// Spring scans for any interface extending Repository or its subtypes
13// and creates a proxy bean for each one
14public interface OrderRepository extends JpaRepository<Order, Long> {
15    // Spring generates the implementation automatically
16}

The auto-configuration chain works like this: @SpringBootApplication enables @EnableAutoConfiguration, which activates JpaRepositoriesAutoConfiguration, which internally calls @EnableJpaRepositories with the application's base package. Any interface extending Spring Data's Repository marker interface (which JpaRepository does) gets a generated proxy.

What @Repository Actually Does

java
1@Target(ElementType.TYPE)
2@Retention(RetentionPolicy.RUNTIME)
3@Documented
4@Component  // Makes it a Spring-managed bean
5public @interface Repository {
6    String value() default "";
7}

@Repository serves two purposes in Spring:

  1. It is a @Component specialization, making the class eligible for component scanning and bean creation.
  2. It enables automatic translation of persistence exceptions (e.g., converting SQLException to Spring's DataAccessException hierarchy).

For JpaRepository interfaces, both functions are already handled: Spring Data creates the bean via its own mechanism, and SimpleJpaRepository (the generated implementation) already has @Repository applied.

When You Might Still Use @Repository

java
1// Custom repository implementation — @Repository IS needed here
2@Repository
3public class CustomUserRepositoryImpl implements CustomUserRepository {
4
5    @PersistenceContext
6    private EntityManager entityManager;
7
8    @Override
9    public List<User> findActiveUsersWithComplexQuery() {
10        return entityManager.createQuery(
11            "SELECT u FROM User u WHERE u.active = true AND u.lastLogin > :date",
12            User.class
13        ).setParameter("date", LocalDate.now().minusDays(30))
14         .getResultList();
15    }
16}

When you write a concrete class that directly uses EntityManager or JDBC without extending a Spring Data interface, @Repository is needed for exception translation and component scanning.

Custom Base Package Scanning

java
1// If your repositories are in a different package
2@SpringBootApplication
3@EnableJpaRepositories(basePackages = "com.example.data.repositories")
4public class MyApplication {
5    public static void main(String[] args) {
6        SpringApplication.run(MyApplication.class, args);
7    }
8}

By default, @EnableJpaRepositories scans the package of the main application class and its sub-packages. If your repository interfaces are in a different package tree, you must specify basePackages explicitly. Even in this case, @Repository is not needed on the interfaces.

The Repository Hierarchy

java
1// Spring Data's interface hierarchy
2public interface Repository<T, ID> { }
3
4public interface CrudRepository<T, ID> extends Repository<T, ID> {
5    <S extends T> S save(S entity);
6    Optional<T> findById(ID id);
7    Iterable<T> findAll();
8    void deleteById(ID id);
9    // ... more CRUD methods
10}
11
12public interface PagingAndSortingRepository<T, ID> extends CrudRepository<T, ID> {
13    Iterable<T> findAll(Sort sort);
14    Page<T> findAll(Pageable pageable);
15}
16
17public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID> {
18    List<T> findAll();
19    void flush();
20    <S extends T> S saveAndFlush(S entity);
21    void deleteAllInBatch();
22    // ... JPA-specific methods
23}

Any interface extending any level of this hierarchy is auto-detected. You choose which level based on what methods you need.

Exception Translation Without @Repository

java
1public interface ProductRepository extends JpaRepository<Product, Long> {
2    // Exception translation works automatically
3    // JPA exceptions → Spring DataAccessException
4}

The proxy created by Spring Data wraps calls in a PersistenceExceptionTranslationInterceptor, which translates JPA exceptions to Spring's DataAccessException hierarchy. This happens regardless of whether you add @Repository to the interface.

Common Pitfalls

  • Adding @Repository out of habit: While harmless, it creates the false impression that the annotation is required. It clutters the code with unnecessary boilerplate. Omit it for Spring Data interfaces.
  • Repository interface not in scanned package: If the interface is outside the base package of @SpringBootApplication, Spring does not find it. Use @EnableJpaRepositories(basePackages = "...") to specify the correct package. This is a scanning issue, not a @Repository issue.
  • Confusing @Repository with @Service or @Component: All three are Spring stereotypes, but @Repository specifically adds persistence exception translation. Using @Service on a repository class loses that behavior.
  • Custom implementations missing @Repository: When you write a concrete *Impl class for custom repository logic using EntityManager directly, you do need @Repository for exception translation. The Spring Data proxy only covers the generated methods.
  • Multiple @EnableJpaRepositories conflicting: If you have multiple @EnableJpaRepositories annotations with overlapping packages, Spring may create duplicate beans. Keep repository scanning configuration in one place.

Summary

  • @Repository is not needed on interfaces extending JpaRepository, CrudRepository, or Repository
  • Spring Data JPA auto-detects repository interfaces through @EnableJpaRepositories (triggered by @SpringBootApplication)
  • SimpleJpaRepository (the generated proxy) already carries @Repository internally
  • Exception translation is handled by the proxy regardless of the annotation
  • Use @Repository only on concrete classes that interact with EntityManager or JDBC directly
  • If repositories are not detected, check package scanning configuration, not @Repository presence

Course illustration
Course illustration

All Rights Reserved.