Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:


1. Overview

Querydsl is an extensive Java framework, which helps with creating and running type-safe queries in a domain-specific language that is similar to SQL.

In this article, we’ll explore Querydsl with the Java Persistence API.

A quick side note here is that HQL for Hibernate was the first target language for Querydsl, but nowadays it supports JPA, JDO, JDBC, Lucene, Hibernate Search, MongoDB, Collections and RDFBean as backends.

2. Preparations

Let’s first add the necessary dependencies to our Maven project:




And now let’s configure the Maven APT plugin:


The JPAAnnotationProcessor will find domain types annotated with jakarta.persistence.Entity annotation and generates query types for them.

3. Queries With Querydsl

Queries are constructed based on generated query types that reflect the properties of your domain types. Also, function/method invocations are constructed in a fully type-safe manner.

The query paths and operations are the same in all implementations and also the Query interfaces have a common base interface.

3.1. An Entity and the Querydsl Query Type

Let’s first define a simple entity we’re going to make use of as we go through examples:

public class Person {

    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String firstname;

    private String surname;
    Person() {

    public Person(String firstname, String surname) {
        this.firstname = firstname;
        this.surname = surname;

    // standard getters and setters


Querydsl will generate a query type with the simple name QPerson into the same package as Person. QPerson can be used as a statically typed variable in Querydsl queries as a representative for the Person type.

First – QPerson has a default instance variable which can be accessed as a static field:

QPerson person = QPerson.person;

Alternatively, you can define your own Person variables like this:

QPerson person = new QPerson("Erich", "Gamma");

3.2. Build Query Using JPAQuery

We can now use JPAQuery instances for our queries:

JPAQuery query = new JPAQuery(entityManager);

Note that the entityManager is a JPA EntityManager.

Let’s now retrieve all the persons with the first name “Kent” as a quick example:

QPerson person = QPerson.person;
List<Person> persons = query.from(person).where(person.firstName.eq("Kent")).list(person);

The from call defines the query source and projection, and the where part defines the filter and list tells Querydsl to return all matched elements.

We can also use multiple filters:

query.from(person).where(person.firstName.eq("Kent"), person.surname.eq("Beck"));



In native JPQL form, the query would be written like this:

select person from Person as person where person.firstName = "Kent" and person.surname = "Beck"

If you want to combine the filters via “or” then use the following pattern:


4. Ordering and Aggregation in Querydsl

Let’s now have a look at how ordering and aggregation work within the Querydsl library.

4.1. Ordering

We’ll start by ordering our results in descending order by the surname field:

QPerson person = QPerson.person;
List<Person> persons = query.from(person)

4.2. Aggregation

Let’s now use a simple aggregation, as we do have a few available (Sum, Avg, Max, Min):

QPerson person = QPerson.person;    
int maxAge = query.from(person).list(person.age.max()).get(0);

4.3. Aggregation With GroupBy

The class provides aggregation functionality which we can use to aggregate query results in memory.

Here’s a quick example where the result is returned as Map with firstname as the key and max age as the value:

QPerson person = QPerson.person;   
Map<String, Integer> results = 

5. Testing With Querydsl

Now, let’s define a DAO implementation using Querydsl – and let’s define the following search operation:

public List<Person> findPersonsByFirstnameQuerydsl(String firstname) {
    JPAQuery query = new JPAQuery(em);
    QPerson person = QPerson.person;
    return query.from(person).where(person.firstname.eq(firstname)).list(person);

And now let’s build a few tests using this new DAO and let’s use Querydsl to search for newly created Person objects (implemented in PersonDao class) and in another test aggregation using GroupBy class is tested:

private PersonDao personDao;

public void givenExistingPersons_whenFindingPersonByFirstName_thenFound() { Person("Erich", "Gamma"));
    Person person = new Person("Kent", "Beck");; Person("Ralph", "Johnson"));

    Person personFromDb =  personDao.findPersonsByFirstnameQuerydsl("Kent").get(0);
    Assert.assertEquals(person.getId(), personFromDb.getId());

public void givenExistingPersons_whenFindingMaxAgeByName_thenFound() { Person("Kent", "Gamma", 20)); Person("Ralph", "Johnson", 35)); Person("Kent", "Zivago", 30));

    Map<String, Integer> maxAge = personDao.findMaxAgeByName();
    Assert.assertTrue(maxAge.size() == 2);
    Assert.assertSame(35, maxAge.get("Ralph"));
    Assert.assertSame(30, maxAge.get("Kent"));

6. Conclusion

This tutorial illustrated how to build a JPA project using Querydsl.

The full implementation of this article can be found in the GitHub project – this is an Eclipse-based maven project, so it should be easy to import and run as it is.

A quick note here is – to run a simple maven build (mvn clean install) to generate the types into target/generated-sources – and then, if you’re using Eclipse – include the folder as a source folder of the project.

Course – LSD (cat=Persistence)

Get started with Spring Data JPA through the reference Learn Spring Data JPA course:

Course – LS – All

Get started with Spring and Spring Boot, through the Learn Spring course:

res – Persistence (eBook) (cat=Persistence)
Comments are open for 30 days after publishing a post. For any issues past this date, use the Contact form on the site.