Spring Data JPA - Class Based Projections

[Updated: Sep 3, 2018, Created: Sep 3, 2018]

In Spring Data JPA, a query projection can also be defined as a DTO (Data Transfer Object). Such classes hold properties for the fields that are supposed to be retrieved. In this case no proxies are created. Also nested projections are not possible.



public class Employee{
  private @Id
  Long id;
  private String name;
  private String dept;
  private int salary;

Defining class-based projection

public class EmployeeInfo {
  private String name;
  private int salary;

  public EmployeeInfo(String name, int salary) { = name;
      this.salary = salary;

As seen in above example, the projection class should have a constructor with properties parameters that should be loaded via query execution. Also If the store optimizes the query execution by limiting the fields to be loaded, the fields to be loaded are determined from the parameter names of the constructor that is exposed.


public interface EmployeeRepository extends CrudRepository<Employee, Long> {
  List<EmployeeInfo> findBy();
  List<EmployeeInfo> findByDept(String dept);

Example Client

public class ExampleClient {

  private EmployeeRepository repo;

  public void run() {
      List<Employee> employees = createEmployees();

      System.out.println(" -- finding all employees --");
      Iterable<Employee> all = repo.findAll();

      System.out.println(" -- finding all EmployeeInfo --");
      List<EmployeeInfo> list = repo.findBy();
      for (EmployeeInfo es : list) {
          System.out.printf("Name: %s, Salary: %s%n", es.getName(), es.getSalary());

      System.out.println(" -- finding the EmployeeInfo in IT dept --");
      list = repo.findByDept("IT");
      for (EmployeeInfo es : list) {
          System.out.printf("Name: %s, Salary: %s%n", es.getName(), es.getSalary());

  private List<Employee> createEmployees() {
      return Arrays.asList(
              Employee.create("Diana", "Admin", 3000),
              Employee.create("Mike", "IT", 1000),
              Employee.create("Rose", "Admin", 4000),
              Employee.create("Sara", "Admin", 3500),
              Employee.create("Tanaka", "IT", 3000),
              Employee.create("Charlie", "IT", 4500)

Main class

public class ExampleMain {

  public static void main(String[] args) {
      AnnotationConfigApplicationContext context =
              new AnnotationConfigApplicationContext(AppConfig.class);
      ExampleClient exampleClient = context.getBean(ExampleClient.class);;
      EntityManagerFactory emf = context.getBean(EntityManagerFactory.class);
 -- finding all employees --
Employee{id=1, name='Diana', dept='Admin', salary=3000}
Employee{id=2, name='Mike', dept='IT', salary=1000}
Employee{id=3, name='Rose', dept='Admin', salary=4000}
Employee{id=4, name='Sara', dept='Admin', salary=3500}
Employee{id=5, name='Tanaka', dept='IT', salary=3000}
Employee{id=6, name='Charlie', dept='IT', salary=4500}
-- finding all EmployeeInfo --
Name: Diana, Salary: 3000
Name: Mike, Salary: 1000
Name: Rose, Salary: 4000
Name: Sara, Salary: 3500
Name: Tanaka, Salary: 3000
Name: Charlie, Salary: 4500
-- finding the EmployeeInfo in IT dept --
Name: Mike, Salary: 1000
Name: Tanaka, Salary: 3000
Name: Charlie, Salary: 4500

Example Project

Dependencies and Technologies Used:

  • spring-data-jpa 2.0.9.RELEASE: Spring Data module for JPA repositories.
    Uses org.springframework:spring-context version 5.0.8.RELEASE
  • hibernate-core 5.3.6.Final: Hibernate's core ORM functionality.
    Implements javax.persistence:javax.persistence-api version 2.2
  • h2 1.4.197: H2 Database Engine.
  • JDK 1.8
  • Maven 3.5.4

Class Based Projections Example Select All Download
  • spring-data-jpa-class-based-projections
    • src
      • main
        • java
          • com
            • logicbig
              • example
          • resources
            • META-INF

    See Also