Defining Repository Interfaces
Defining Repository Interfaces
To define a repository interface, you first need to define a domain class-specific repository
interface. The interface must extend Repository and be typed to the domain class and
an ID type. If you want to expose CRUD methods for that domain type, you may extend
CrudRepository , or one of its variants instead of Repository .
The typical approach is to extend CrudRepository , which gives you methods for CRUD
functionality. CRUD stands for Create, Read, Update, Delete. With version 3.0 we also
introduced ListCrudRepository which is very similar to the CrudRepository but for
those methods that return multiple entities it returns a List instead of an Iterable
which you might find easier to use.
If you are using Kotlin you might pick CoroutineCrudRepository which utilizes Kotlin’s
coroutines.
If you do not want to extend Spring Data interfaces, you can also annotate your repository
interface with @RepositoryDefinition . Extending one of the CRUD repository interfaces
exposes a complete set of methods to manipulate your entities. If you prefer to be selective
about the methods being exposed, copy the methods you want to expose from the CRUD
repository into your domain repository. When doing so, you may change the return type of
methods. Spring Data will honor the return type if possible. For example, for methods
returning multiple entities you may choose Iterable<T> , List<T> , Collection<T> or
a VAVR list.
If many repositories in your application should have the same set of methods you can
define your own base interface to inherit from. Such an interface must be annotated with
@NoRepositoryBean . This prevents Spring Data to try to create an instance of it directly
and failing because it can’t determine the entity for that repository, since it still contains a
generic type variable.
The following example shows how to selectively expose CRUD methods ( findById and
save , in this case):
In the prior example, you defined a common base interface for all your domain repositories
and exposed findById(…) as well as save(…) .These methods are routed into the base
repository implementation of the store of your choice provided by Spring Data (for example,
if you use JPA, the implementation is SimpleJpaRepository ), because they match the
method signatures in CrudRepository . So the UserRepository can now save users,
find individual users by ID, and trigger a query to find Users by email address.
The intermediate repository interface is annotated with @NoRepositoryBean . Make sure you
add that annotation to all repository interfaces for which Spring Data should not create instances
at runtime.
2. If the domain class is annotated with the module-specific type annotation, it is a valid
candidate for the particular Spring Data module. Spring Data modules accept either
third-party annotations (such as JPA’s @Entity ) or provide their own annotations
(such as @Document for Spring Data MongoDB and Spring Data Elasticsearch).
The following example shows a repository that uses module-specific interfaces (JPA in this
case):
JAVA
interface MyRepository extends JpaRepository<User, Long> { }
@NoRepositoryBean
interface MyBaseRepository<T, ID> extends JpaRepository<T, ID> { … }
JAVA
interface AmbiguousRepository extends Repository<User, Long> { … }
@NoRepositoryBean
interface MyBaseRepository<T, ID> extends CrudRepository<T, ID> { … }
The following example shows a repository that uses domain classes with annotations:
JAVA
interface PersonRepository extends Repository<Person, Long> { … }
@Entity
class Person { … }
@Document
class User { … }
The following bad example shows a repository that uses domain classes with mixed
annotations:
JAVA
interface JpaPersonRepository extends Repository<Person, Long> { … }
@Entity
@Document
class Person { … }
This example shows a domain class using both JPA and Spring Data MongoDB
annotations. It defines two repositories, JpaPersonRepository and
MongoDBPersonRepository . One is intended for JPA and the other for MongoDB
usage. Spring Data is no longer able to tell the repositories apart, which leads to
undefined behavior.
Repository type details and distinguishing domain class annotations are used for strict
repository configuration to identify repository candidates for a particular Spring Data
module. Using multiple persistence technology-specific annotations on the same domain
type is possible and enables reuse of domain types across multiple persistence
technologies. However, Spring Data can then no longer determine a unique module with
which to bind the repository.
The last way to distinguish repositories is by scoping repository base packages. Base
packages define the starting points for scanning for repository interface definitions, which
implies having repository definitions located in the appropriate packages. By default,
annotation-driven configuration uses the package of the configuration class. The base
package in XML-based configuration is mandatory.