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

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. Overview

In this short tutorial, we'll discuss how to create a read-only Spring Data Repository.

It's sometimes necessary to read data out of a database without having to modify it. In this case, having a read-only Repository interface would be perfect.

It'll provide the ability to read data without the risk of anyone changing it.

2. Extending Repository

Let's begin with a Spring Boot project that includes the spring-boot-starter-data-jpa dependency:


Included in this dependency is Spring Data's popular CrudRepository interface, which comes with methods for all the basic CRUD operations (create, read, update, delete) that most applications need. However, it includes several methods that modify data, and we need a repository that only has the ability to read data.

CrudRepository actually extends another interface called Repository. We can also extend this interface to fit our needs.

Let's create a new interface that extends Repository:

public interface ReadOnlyRepository<T, ID> extends Repository<T, ID> {
    Optional<T> findById(ID id);
    List<T> findAll();

Here, we've only defined two read-only methods. The entity that is accessed by this repository will be safe from any modification.

It is also important to note that we must use the @NoRepositoryBean annotation to tell Spring that we want this repository to remain generic. This allows us to reuse our read-only repository for as many different entities as we want.

Next, we'll see how to tie an entity to our new ReadOnlyRepository.

3. Extending ReadOnlyRepository

Let's assume we have a simple Book entity that we would like to access:

public class Book {
    private Long id;
    private String author;
    private String title;

    //getters and setters

Now that we have a persistable entity, we can create a repository interface that inherits from our ReadOnlyRepository:

public interface BookReadOnlyRepository extends ReadOnlyRepository<Book, Long> {
    List<Book> findByAuthor(String author);
    List<Book> findByTitle(String title);

In addition to the two methods that it inherits, we've added two more Book-specific read-only methods: findByAuthor() and findByTitle(). In total, this repository has access to four read-only methods.

Finally, let's write a test that will ensure the functionality of our BookReadOnlyRepository:

public void givenBooks_whenUsingReadOnlyRepository_thenGetThem() {
    Book aChristmasCarolCharlesDickens = new Book();
    aChristmasCarolCharlesDickens.setTitle("A Christmas Carol");
    aChristmasCarolCharlesDickens.setAuthor("Charles Dickens");

    Book greatExpectationsCharlesDickens = new Book();
    greatExpectationsCharlesDickens.setTitle("Great Expectations");
    greatExpectationsCharlesDickens.setAuthor("Charles Dickens");

    Book greatExpectationsKathyAcker = new Book();
    greatExpectationsKathyAcker.setTitle("Great Expectations");
    greatExpectationsKathyAcker.setAuthor("Kathy Acker");

    List<Book> charlesDickensBooks = bookReadOnlyRepository.findByAuthor("Charles Dickens");
    Assertions.assertEquals(2, charlesDickensBooks.size());

    List<Book> greatExpectationsBooks = bookReadOnlyRepository.findByTitle("Great Expectations");
    Assertions.assertEquals(2, greatExpectationsBooks.size());

    List<Book> allBooks = bookReadOnlyRepository.findAll();
    Assertions.assertEquals(3, allBooks.size());
    Long bookId = allBooks.get(0).getId();
    Book book = bookReadOnlyRepository.findById(bookId).orElseThrow(NoSuchElementException::new);

In order to save the books into the database before reading them back out, we created a BookRepository that extends CrudRepository in the test scope. This repository is not needed in the main project scope but was necessary for this test.

public interface BookRepository
  extends BookReadOnlyRepository, CrudRepository<Book, Long> {}

We were able to test all four of our read-only methods and can now reuse the ReadOnlyRepository interface for other entities.

4. Conclusion

We learned how to extend Spring Data's Repository interface in order to create a reusable read-only repository. After that, we tied it to a simple Book entity and wrote a test that proved its functionality works as we would expect.

As always, a working example of this code can be found over 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
Inline Feedbacks
View all comments
Comments are closed on this article!