Spring Boot Data JPA — Part IV (Projections)

Mahesh Bonagiri
Javarevisited
Published in
4 min readSep 6, 2021

Part I (Getting started)|Part II (Pagination & Sorting)| Part III (Auditing)

In Previous posts I explained how to get started, Pagination & Sorting and Auditing with Spring boot Data JPA. In this post we will discuss how to use Projections with Spring Data.

When using Spring Data JPA, the repository typically returns one or more instances of the root class. There may be cases where we do not want an entire entity from the query method but are interested only in few attributes of that entity or subset of that entity with some manipulation in it. This is where projections come in handy.

Let’s start:

we will use Spring Initializer generate the base for our project, in my previous post I have explained how to get starting with Spring Boot + Eclipse.

Define a Simple Entity

Let's create an Entity called BookEntity as shown below (we can reuse the entities created in the previous post).

Each of our Book instances has a unique identifier: id, its name, author, price and audit information like createdDate/modifiedDate/createdBy/modifiedBy

Repository Interface:

Let’s have a look at our BookRepoisitory, which extends the JpaRepository.

Interface Based Projections

In this type, we create an interface with only getter methods of properties we want from an entity class. This interface will be the return type of query method we write in Spring Data JPA’s Repository interface.

Close Projection:

In Close Projection, the getter methods of interface match exactly with the getter methods of Entity’s properties. Looking at the Book Entity, we can see it has many properties, yet not all of them are helpful. For example, audit information is not required all the time.

Let’s declare a projection interface for the Book Entity as shown below.

update BookRepository as shown below.

Defining a repository method with a projection interface and entity class is pretty much the same. The only difference is that in interface-based projection interface is used as the element type in the returned collection.

Create an Application Class

Create SpringbootDataJpaProjectionsApplication class as shown below. Using CommandLineRunner we will first save few records and then later fetch those records.

When you run your application, you should see output similar to the following:

As you can see above, the generated SQL statement only selects the columns mapped by the interface.

Open Projection:

in Open Projection we will create an interface with getter methods of selective properties only but in addition to that, we also use SpEL expression. The SpEL expression will help us to define a new property from existing properties. Like in the above case if we want a property “Book And Author Name” then we can define it using SpEL expression and @Value annotation.

update BookView.java as show below.

Running above SpringbootDataJpaProjectionsApplication, you should see output similar to the following

As you can see above, Open projections have a drawback. Spring Data cannot optimize query execution as it doesn’t know in advance which properties will be used. Thus, we should only use open projections when closed projections aren’t capable of handling our requirements.

Class Based Projections:

In Class-based Projections we use classes instead of interfaces. We create Projection class which contains only those properties we were interested in the Entity class and its class hierarchy.

Let’s declare a projection class for the Book Entity as shown below.

Now, let’s update BookRepository as shown below.

update SpringbootDataJpaProjectionsApplication as shown below.

Running above SpringbootDataJpaProjectionsApplication, you should see output similar to the following

As you can see, Entity based projections pulled all the fields, class/Interfaced based projections pulled only fields we defined.

Dynamic Projections:

An entity class may have many projections. In some cases, we may use a certain type, but in other cases, we may need another type. Sometimes, we also need to use the entity class itself.

Defining separate repository interfaces or methods just to support multiple return types is cumbersome. To deal with this problem, Spring Data provides a better solution: dynamic projections.

We can apply dynamic projections just by declaring a repository method with a Class parameter:

Now, let’s update BookRepository as shown below.

Lets update SpringbootDataJpaProjectionsApplication as shown below.

Running above SpringbootDataJpaProjectionsApplication, you should see output similar to the following

Bonus Point:

In some cases, our Projection class contains a large number of properties and we may want to use the same class for different requirements which requires different sets of properties. Creating a new constructor with a number of arguments for all such requirements may not be a good practice. In such situations, we add a constructor in our Projection class with a Map. The Map contains alias of selected property as a key(string) and its value. Though we use the same projection class, only interested properties will be set here.

Add CustomBook as shown below

Update BookRepository as shown below.

update SpringbootDataJpaProjectionsApplication as shown below.

Running above SpringbootDataJpaProjectionsApplication, you should see output similar to the following

Conclusion:

If you would like to refer to the full code, do check https://github.com/projectk-user1/Springboot-learning.git

Please do refer my other articles on Spring boot.

--

--