Expand Authors Top

If you have a few years of experience in the Java ecosystem and you’d like to share that with the community, have a look at our Contribution Guidelines.

Expanded Audience – Frontegg – Security (partner)
announcement - icon User management is very complex, when implemented properly. No surprise here.

Not having to roll all of that out manually, but instead integrating a mature, fully-fledged solution - yeah, that makes a lot of sense.
That's basically what Frontegg is - User Management for your application. It's focused on making your app scalable, secure and enjoyable for your users.
From signup to authentication, it supports simple scenarios all the way to complex and custom application logic.

Have a look:

>> Elegant User Management, Tailor-made for B2B SaaS

NPI – JPA Buddy – JPA (partner)
announcement - icon

JPA is huge! It covers nearly every aspect of communication between relational databases and the Java application and is deeply integrated into all major frameworks.

If you're using IntelliJ, JPA Buddy is super helpful. The plugin gently guides you through the subtleties of the most popular JPA implementations, visually reminds you of JPA features, generates code that follows best practices, and integrates intelligent inspections to improve your existing persistence code.

More concretely, it provides powerful tooling to generate Spring Data JPA repositories and methods, Flyway Versioned Migrations, Liquibase Differential Changelogs, DDL and SQL statements, DTO objects, and MapStruct interfaces.

Oh, and it actually generates JPA entities from an existing database and gradually update the data model as the database evolves! Yeah.

>> Become a lot more productive with JPA Buddy

November Discount Launch 2022 – Top
We’re finally running a Black Friday launch. All Courses are 30% off until tomorrow:


November Discount Launch 2022 – TEMP TOP (NPI)
We’re finally running a Black Friday launch. All Courses are 30% off until tomorrow:



1. Introduction

When modeling a real-world system or process, domain-driven design (DDD) style repositories are a good option. For this very purpose, we can use Spring Data JPA as our data access abstraction layer.

If you are new to this concept check out this introductory tutorial to help get you up to speed.

In this tutorial, we'll focus on the concept of creating custom as well as composable repositories which are created using smaller repositories called fragments.

2. Maven Dependencies

The option to create composable repositories is available starting with Spring 5.

Let's add the required dependency for Spring Data JPA:


We'd also need to set up a data source in order for our data access layer to work. It's a good idea to set up an in-memory database like H2 for development and quick testing.

3. Background

3.1. Hibernate as JPA Implementation

Spring Data JPA, by default, uses Hibernate as the JPA implementation. We can easily confuse one with the other or compare them but they serve different purposes.

Spring Data JPA is the data access abstraction layer below which we can use any implementation. We could, for instance, switch out Hibernate in favor of EclipseLink.

3.2. Default Repositories

In a lot of cases, we wouldn't need to write any queries ourselves.

Instead, we only need to create interfaces which in turn extend the generic Spring data repository interfaces:

public interface LocationRepository extends JpaRepository<Location, Long> {

And this, in itself, would allow us to do common operations – CRUD, paging, and sorting – on the Location object which has a primary key of type Long.

Furthermore, Spring Data JPA comes equipped with a query builder mechanism which provides the ability to generate queries on our behalf using method name conventions:

public interface StoreRepository extends JpaRepository<Store, Long> {
    List<Store> findStoreByLocationId(Long locationId);

3.3. Custom Repositories

If required, we can enrich our model repository by writing a fragment interface and implementing the desired functionality. This can then be injected in our own JPA repository.

For example, here we are enriching our ItemTypeRepository by extending a fragment repository:

public interface ItemTypeRepository 
  extends JpaRepository<ItemType, Long>, CustomItemTypeRepository {

Here CustomItemTypeRepository is another interface:

public interface CustomItemTypeRepository {
    void deleteCustomById(ItemType entity);

Its implementation can be a repository of any kind, not just JPA:

public class CustomItemTypeRepositoryImpl implements CustomItemTypeRepository {
    private EntityManager entityManager;

    public void deleteCustomById(ItemType itemType) {

We just need to make sure that it has the postfix Impl. However, we can set a custom postfix by using the following XML configuration:

<repositories base-package="com.baeldung.repository" repository-impl-postfix="CustomImpl" />

or by using this annotation:

  basePackages = "com.baeldung.repository", repositoryImplementationPostfix = "CustomImpl")

4. Composing Repositories Using Multiple Fragments

Up until a few releases ago, we could only extend our repository interfaces using a single custom implementation. This was a limitation because of which we'd have to bring all related functionality into a single object.

Needless to say, for larger projects with complex domain models, this lead to bloated classes.

Now with Spring 5, we have the option to enrich our JPA repository with multiple fragment repositories. Again, the requirement remains that we have these fragments as interface-implementation pairs.

To demonstrate this, let’s create two fragments:

public interface CustomItemTypeRepository {
    void deleteCustom(ItemType entity);
    void findThenDelete(Long id);

public interface CustomItemRepository {
    Item findItemById(Long id);
    void deleteCustom(Item entity);
    void findThenDelete(Long id);

Of course, we'd need to write their implementations. But instead of plugging these custom repositories – with related functionalities – in their own JPA repositories, we can extend the functionality of a single JPA repository:

public interface ItemTypeRepository 
  extends JpaRepository<ItemType, Long>, CustomItemTypeRepository, CustomItemRepository {

Now, we'd have all the linked functionality in one single repository.

5. Dealing with Ambiguity

Since we're inheriting from multiple repositories, we may have trouble figuring out which of our implementations would be used in case of a clash. For instance, in our example, both fragment repositories have a method, findThenDelete(), with the same signature.

In this scenario, the order of the declaration of the interfaces is used to resolve the ambiguity. Consequently, in our case, the method inside CustomItemTypeRepository will be used since it's declared first.

We can test this by using this test case:

public void givenItemAndItemTypeWhenDeleteThenItemTypeDeleted() {
    Optional<ItemType> itemType = composedRepository.findById(1L);

    Item item = composedRepository.findItemById(2L);

    Optional<ItemType> sameItemType = composedRepository.findById(1L);

    Item sameItem = composedRepository.findItemById(2L);

6. Conclusion

In this article, we took a look at the different ways through which we can use Spring Data JPA repositories. We saw that Spring makes it simple to perform database operations on our domain objects without writing much code or even SQL queries.

This support is considerably customizable through the use of composable repositories.

The code snippets from this article are available as a Maven project here on GitHub.


November Discount Launch 2022 – Bottom
We’re finally running a Black Friday launch. All Courses are 30% off until tomorrow:


Persistence footer banner
Comments are closed on this article!