Spring Data JPA makes it easy to interact with JPA data sources inside a Spring application. Projections are a mechanism for returning a subset of data from a JPA repository. In this post I’ll discuss a unique way of specifying the desired projection when invoking repository methods.
Consider the following repository:
public interface UserRepository extends CrudRepository {}
A User entity is defined as:
public Long getId(); public String getUsername(); public String getPasswordHint(); public String getFullName(); public String getBio();
Assume we need to work with two different views of the user inside our application: an in-network view consisting of id, username, fullName, bio and an out-of-network view consisting of id, username, fullName.
We’ll create two projections; these are simply interfaces that expose the desired property getters, e.g.
public interface ExternalUserView { public Long getId(); public String getUsername(); public String getFullName(); }
Projections are often utilized by adding new interface methods to the repository, e.g.
List<InternalUserView> finalAllInternalUsersBy(); List<ExternalUserView> finalAllExternalUsersBy(); ...
However, this approach can lead to method clutter if you have several projections and/or custom query methods. An improved approach involves passing the desired projection as a parameter:
<T> List<T> findAllBy(Class<T> clazz); <T> Optional<T> findById(Long id, Class<T> clazz);
The projection can now be specified when calling a repository method, e.g.
List<InternalUserView> users = repo.findAllBy(InternalUserView.class);
If you’re making significant use of projections, consider using this approach to keep your code clean and terse. A working example is available here.