Partner – Microsoft – NPI EA (cat = Baeldung)
announcement - icon

Azure Container Apps is a fully managed serverless container service that enables you to build and deploy modern, cloud-native Java applications and microservices at scale. It offers a simplified developer experience while providing the flexibility and portability of containers.

Of course, Azure Container Apps has really solid support for our ecosystem, from a number of build options, managed Java components, native metrics, dynamic logger, and quite a bit more.

To learn more about Java features on Azure Container Apps, visit the documentation page.

You can also ask questions and leave feedback on the Azure Container Apps GitHub page.

Partner – Microsoft – NPI EA (cat= Spring Boot)
announcement - icon

Azure Container Apps is a fully managed serverless container service that enables you to build and deploy modern, cloud-native Java applications and microservices at scale. It offers a simplified developer experience while providing the flexibility and portability of containers.

Of course, Azure Container Apps has really solid support for our ecosystem, from a number of build options, managed Java components, native metrics, dynamic logger, and quite a bit more.

To learn more about Java features on Azure Container Apps, you can get started over on the documentation page.

And, you can also ask questions and leave feedback on the Azure Container Apps GitHub page.

Partner – Orkes – NPI EA (cat=Spring)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

Partner – Orkes – NPI EA (tag=Microservices)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

eBook – Guide Spring Cloud – NPI EA (cat=Spring Cloud)
announcement - icon

Let's get started with a Microservice Architecture with Spring Cloud:

>> Join Pro and download the eBook

eBook – Mockito – NPI EA (tag = Mockito)
announcement - icon

Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.

Get started with mocking and improve your application tests using our Mockito guide:

Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Reactive – NPI EA (cat=Reactive)
announcement - icon

Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:

>> Join Pro and download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Jackson – NPI EA (cat=Jackson)
announcement - icon

Do JSON right with Jackson

Download the E-book

eBook – HTTP Client – NPI EA (cat=Http Client-Side)
announcement - icon

Get the most out of the Apache HTTP Client

Download the E-book

eBook – Maven – NPI EA (cat = Maven)
announcement - icon

Get Started with Apache Maven:

Download the E-book

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

eBook – RwS – NPI EA (cat=Spring MVC)
announcement - icon

Building a REST API with Spring?

Download the E-book

Course – LS – NPI EA (cat=Jackson)
announcement - icon

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

>> LEARN SPRING
Course – RWSB – NPI EA (cat=REST)
announcement - icon

Explore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:

>> The New “REST With Spring Boot”

Course – LSS – NPI EA (cat=Spring Security)
announcement - icon

Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.

I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.

You can explore the course here:

>> Learn Spring Security

Course – LSD – NPI EA (tag=Spring Data JPA)
announcement - icon

Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.

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

>> CHECK OUT THE COURSE

Partner – MongoDB – NPI EA (tag=MongoDB)
announcement - icon

Traditional keyword-based search methods rely on exact word matches, often leading to irrelevant results depending on the user's phrasing.

By comparison, using a vector store allows us to represent the data as vector embeddings, based on meaningful relationships. We can then compare the meaning of the user’s query to the stored content, and retrieve more relevant, context-aware results.

Explore how to build an intelligent chatbot using MongoDB Atlas, Langchain4j and Spring Boot:

>> Building an AI Chatbot in Java With Langchain4j and MongoDB Atlas

Partner – LambdaTest – NPI EA (cat=Testing)
announcement - icon

Accessibility testing is a crucial aspect to ensure that your application is usable for everyone and meets accessibility standards that are required in many countries.

By automating these tests, teams can quickly detect issues related to screen reader compatibility, keyboard navigation, color contrast, and other aspects that could pose a barrier to using the software effectively for people with disabilities.

Learn how to automate accessibility testing with Selenium and the LambdaTest cloud-based testing platform that lets developers and testers perform accessibility automation on over 3000+ real environments:

Automated Accessibility Testing With Selenium

1. Introduction

This is an introductory article to get you up and running with the powerful Querydsl API for data persistence.

The goal here is to give you the practical tools to add Querydsl to your project, understand the structure and purpose of the generated classes, and get a basic understanding of how to write type-safe database queries for the most common scenarios.

2. The Purpose of Querydsl

Object-relational mapping frameworks are at the core of Enterprise Java. These compensate for the mismatch between the object-oriented approach and the relational database model. They also allow developers to write cleaner and more concise persistence code and domain logic.

However, one of the most difficult design choices for an ORM framework is the API for building correct and type-safe queries.

One of the most widely used Java ORM frameworks, Hibernate (and also closely related JPA standard), proposes a string-based query language HQL (JPQL) very similar to SQL. The obvious drawbacks of this approach are the lack of type safety and the absence of static query checking. Also, in more complex cases (for instance, when the query needs to be constructed at runtime depending on some conditions), building an HQL query typically involves the concatenation of strings which is usually very unsafe and error-prone.

Starting with JPA 2.0 standard brought an improvement in the form of Criteria Query API — a new and type-safe method of building queries that took advantage of metamodel classes generated during annotation preprocessing. Unfortunately, being groundbreaking in its essence, Criteria Query API ended up very verbose and practically unreadable. Here’s an example from the Jakarta EE tutorial for generating a query as simple as SELECT p FROM Pet p:

EntityManager em = ...;
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
Root<Pet> pet = cq.from(Pet.class);
cq.select(pet);
TypedQuery<Pet> q = em.createQuery(cq);
List<Pet> allPets = q.getResultList();

No wonder that a more adequate Querydsl library soon emerged, based on the same idea of generated metadata classes, yet implemented with a fluent and readable API.

3. Querydsl Class Generation

Let’s start with generating and exploring the magical metaclasses that account for the fluent API of Querydsl.

3.1. Adding Querydsl to Maven Build

Including Querydsl in your project is as simple as adding several dependencies to your build file and configuring a plugin for processing JPA annotations. Let’s start with the dependencies. The version of Querydsl libraries should be extracted to a separate property inside the <project><properties> section, as follows (for the latest version of Querydsl libraries, check the Maven Central repository):

<properties>
    <querydsl.version>5.0.0</querydsl.version>
</properties>

Next, add the following dependencies to the <project><dependencies> section of your pom.xml file:

<dependencies>

    <dependency>
        <groupId>com.querydsl</groupId>
        <artifactId>querydsl-apt</artifactId>
        <version>${querydsl.version}</version>
        <classifier>jakarta</classifier>
        <scope>provided</scope>
    </dependency>

    <dependency>
        <groupId>com.querydsl</groupId>
        <artifactId>querydsl-jpa</artifactId>
        <classifier>jakarta</classifier>
        <version>${querydsl.version}</version>
    </dependency>

</dependencies>

The querydsl-apt dependency is an annotation processing tool (APT) — implementation of corresponding Java API that allows the processing of annotations in source files before they move on to the compilation stage. This tool generates the so-called Q-types — classes that directly relate to the entity classes of your application, but are prefixed with the letter Q. For instance, if you have a User class marked with the @Entity annotation in your application, then the generated Q-type will reside in a QUser.java source file.

The provided scope of the querydsl-apt dependency means that this jar should be made available only at build time, but not included in the application artifact.

The querydsl-jpa library is the Querydsl itself, designed to be used together with a JPA application.

To configure the annotation processing plugin that takes advantage of querydsl-apt, add the following plugin configuration to your pom – inside the <project><build><plugins> element:

<plugin>
    <groupId>com.mysema.maven</groupId>
    <artifactId>apt-maven-plugin</artifactId>
    <version>1.1.3</version>
    <executions>
        <execution>
            <goals>
                <goal>process</goal>
            </goals>
            <configuration>
                <outputDirectory>target/generated-sources/java</outputDirectory>
                <processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
            </configuration>
        </execution>
    </executions>
</plugin>

This plugin makes sure that the Q-types are generated during the process goal of the Maven build. The outputDirectory configuration property points to the directory where the Q-type source files will be generated. The value of this property will be useful later on when you’ll go exploring the Q-files.

You should also add this directory to the source folders of the project, if your IDE does not do this automatically — consult the documentation for your favourite IDE on how to do that.

For this article, we will use a simple JPA model of a blog service, consisting of Users and their BlogPosts with a one-to-many relationship between them:

@Entity
public class User {

    @Id
    @GeneratedValue
    private Long id;

    private String login;

    private Boolean disabled;

    @OneToMany(cascade = CascadeType.PERSIST, mappedBy = "user")
    private Set<BlogPost> blogPosts = new HashSet<>(0);

    // getters and setters

}

@Entity
public class BlogPost {

    @Id
    @GeneratedValue
    private Long id;

    private String title;

    private String body;

    @ManyToOne
    private User user;

    // getters and setters

}

To generate Q-types for your model, simply run:

mvn compile

3.2. Exploring Generated Classes

Now go to the directory specified in the outputDirectory property of apt-maven-plugin (target/generated-sources/java in our example). You will see a package and class structure that directly mirrors your domain model, except all the classes start with the letter Q (QUser and QBlogPost in our case).

Open the file QUser.java. This is your entry point to building all queries that have User as a root entity. The first thing you’ll notice is the @Generated annotation which means that this file was automatically generated and should not be edited manually. Should you change any of your domain model classes, you will have to run mvn compile again to regenerate all of the corresponding Q-types.

Aside from several QUser constructors present in this file, you should also take notice of a public static final instance of the QUser class:

public static final QUser user = new QUser("user");

This is the instance that you can use in most of your Querydsl queries to this entity, except when you need to write some more complex queries, like joining several different instances of a table in a single query.

The last thing that should be noted is that for every field of the entity class, there is a corresponding *Path field in the Q-type, like NumberPath id, StringPath login and SetPath blogPosts in the QUser class (notice that the name of the field corresponding to Set is pluralized). These fields are used as parts of fluent query API that we will encounter later on.

4. Querying With Querydsl

4.1. Simple Querying and Filtering

To build a query, first, we’ll need an instance of a JPAQueryFactory, which is a preferred way of starting the building process. The only thing that JPAQueryFactory needs is an EntityManager, which should already be available in your JPA application via EntityManagerFactory.createEntityManager() call or @PersistenceContext injection.

EntityManagerFactory emf = 
  Persistence.createEntityManagerFactory("com.baeldung.querydsl.intro");
EntityManager em = entityManagerFactory.createEntityManager();
JPAQueryFactory queryFactory = new JPAQueryFactory(JPQLTemplates.DEFAULT, em);

Now let’s create our first query:

QUser user = QUser.user;

User c = queryFactory.selectFrom(user)
  .where(user.login.eq("David"))
  .fetchOne();

Notice we’ve defined a local variable QUser user and initialized it with QUser.user static instance. This is done purely for brevity, alternatively, you may import the static QUser.user field.

The selectFrom method of the JPAQueryFactory starts building a query. We pass it to the QUser instance and continue building the conditional clause of the query with the .where() method. The user.login is a reference to a StringPath field of the QUser class that we’ve seen before. The StringPath object also has the .eq() method that allows to fluently continue building the query by specifying the field equality condition.

Finally, to fetch the value from the database into the persistence context, we end the building chain with the call to the fetchOne() method. This method returns null if the object can’t be found, but throws a NonUniqueResultException if there are multiple entities satisfying the .where() condition.

4.2. Ordering and Grouping

Now let’s fetch all users in a list, sorted by their login in ascension order.

List<User> c = queryFactory.selectFrom(user)
  .orderBy(user.login.asc())
  .fetch();

This syntax is possible because the *Path classes have the .asc() and .desc() methods. You can also specify several arguments for the .orderBy() method to sort by multiple fields.

Now let’s try something more difficult. Suppose we need to group all posts by title and count duplicating titles. This is done with the .groupBy() clause. We’ll also want to order the titles by resulting occurrence count.

NumberPath<Long> count = Expressions.numberPath(Long.class, "c");

List<Tuple> userTitleCounts = queryFactory.select(
  blogPost.title, blogPost.id.count().as(count))
  .from(blogPost)
  .groupBy(blogPost.title)
  .orderBy(count.desc())
  .fetch();

We selected the blog post title and count of duplicates, grouping by title and then ordering by aggregated count. Notice we first created an alias for the count() field in the .select() clause, because we needed to reference it in the .orderBy() clause.

4.3. Complex Queries With Joins and Subqueries

Let’s find all users that wrote a post titled “Hello World!” For such query, we could use an inner join. Notice we’ve created an alias blogPost for the joined table to reference it in the .on() clause:

QBlogPost blogPost = QBlogPost.blogPost;

List<User> users = queryFactory.selectFrom(user)
  .innerJoin(user.blogPosts, blogPost)
  .on(blogPost.title.eq("Hello World!"))
  .fetch();

Now let’s try to achieve the same with a subquery:

List<User> users = queryFactory.selectFrom(user)
  .where(user.id.in(
    JPAExpressions.select(blogPost.user.id)
      .from(blogPost)
      .where(blogPost.title.eq("Hello World!"))))
  .fetch();

As we can see, subqueries are very similar to queries, and they are also quite readable, but they start with JPAExpressions factory methods. To connect subqueries with the main query, as always, we reference the aliases defined and used earlier.

4.4. Modifying Data

JPAQueryFactory allows not only constructing queries but also modifying and deleting records. Let’s change the user’s login and disable the account:

queryFactory.update(user)
  .where(user.login.eq("Ash"))
  .set(user.login, "Ash2")
  .set(user.disabled, true)
  .execute();

We can have any number of .set() clauses we want for different fields. The .where() clause is not necessary, so we can update all the records at once.

To delete the records matching a certain condition, we can use a similar syntax:

queryFactory.delete(user)
  .where(user.login.eq("David"))
  .execute();

The .where() clause is also not necessary, but be careful, because omitting the .where() clause results in deleting all of the entities of a certain type.

You may wonder, why JPAQueryFactory doesn’t have the .insert() method. This is a limitation of the JPA Query interface. The underlying jakarta.persistence.Query.executeUpdate() method is capable of executing update and delete but not insert statements. To insert data, you should simply persist the entities with EntityManager.

If you still want to take advantage of a similar Querydsl syntax for inserting data, you should use SQLQueryFactory class that resides in the querydsl-sql library.

5. Conclusion

In this article, we’ve discovered a powerful and type-safe API for persistent object manipulation that is provided by Querydsl.

We’ve learned to add Querydsl to the project and explored the generated Q-types. We’ve also covered some typical use cases and enjoyed their conciseness and readability.

The code backing this article is available on GitHub. Once you're logged in as a Baeldung Pro Member, start learning and coding on the project.

Finally, there are of course many more features that Querydsl provides, including working with raw SQL, non-persistent collections, NoSQL databases and full-text search – and we’ll explore some of these in future articles.

Baeldung Pro – NPI EA (cat = Baeldung)
announcement - icon

Baeldung Pro comes with both absolutely No-Ads as well as finally with Dark Mode, for a clean learning experience:

>> Explore a clean Baeldung

Once the early-adopter seats are all used, the price will go up and stay at $33/year.

Partner – Microsoft – NPI EA (cat = Baeldung)
announcement - icon

Azure Container Apps is a fully managed serverless container service that enables you to build and deploy modern, cloud-native Java applications and microservices at scale. It offers a simplified developer experience while providing the flexibility and portability of containers.

Of course, Azure Container Apps has really solid support for our ecosystem, from a number of build options, managed Java components, native metrics, dynamic logger, and quite a bit more.

To learn more about Java features on Azure Container Apps, visit the documentation page.

You can also ask questions and leave feedback on the Azure Container Apps GitHub page.

Partner – Microsoft – NPI EA (cat = Spring Boot)
announcement - icon

Azure Container Apps is a fully managed serverless container service that enables you to build and deploy modern, cloud-native Java applications and microservices at scale. It offers a simplified developer experience while providing the flexibility and portability of containers.

Of course, Azure Container Apps has really solid support for our ecosystem, from a number of build options, managed Java components, native metrics, dynamic logger, and quite a bit more.

To learn more about Java features on Azure Container Apps, visit the documentation page.

You can also ask questions and leave feedback on the Azure Container Apps GitHub page.

Partner – Orkes – NPI EA (cat = Spring)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

Partner – Orkes – NPI EA (tag = Microservices)
announcement - icon

Modern software architecture is often broken. Slow delivery leads to missed opportunities, innovation is stalled due to architectural complexities, and engineering resources are exceedingly expensive.

Orkes is the leading workflow orchestration platform built to enable teams to transform the way they develop, connect, and deploy applications, microservices, AI agents, and more.

With Orkes Conductor managed through Orkes Cloud, developers can focus on building mission critical applications without worrying about infrastructure maintenance to meet goals and, simply put, taking new products live faster and reducing total cost of ownership.

Try a 14-Day Free Trial of Orkes Conductor today.

eBook – HTTP Client – NPI EA (cat=HTTP Client-Side)
announcement - icon

The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:

>> Download the eBook

eBook – Java Concurrency – NPI EA (cat=Java Concurrency)
announcement - icon

Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.

Get started with understanding multi-threaded applications with our Java Concurrency guide:

>> Download the eBook

eBook – Java Streams – NPI EA (cat=Java Streams)
announcement - icon

Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.

But these can also be overused and fall into some common pitfalls.

To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:

>> Join Pro and download the eBook

eBook – Persistence – NPI EA (cat=Persistence)
announcement - icon

Working on getting your persistence layer right with Spring?

Explore the eBook

Partner – MongoDB – NPI EA (tag=MongoDB)
announcement - icon

Traditional keyword-based search methods rely on exact word matches, often leading to irrelevant results depending on the user's phrasing.

By comparison, using a vector store allows us to represent the data as vector embeddings, based on meaningful relationships. We can then compare the meaning of the user’s query to the stored content, and retrieve more relevant, context-aware results.

Explore how to build an intelligent chatbot using MongoDB Atlas, Langchain4j and Spring Boot:

>> Building an AI Chatbot in Java With Langchain4j and MongoDB Atlas

Course – LS – NPI EA (cat=REST)

announcement - icon

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

>> CHECK OUT THE COURSE

eBook Jackson – NPI EA – 3 (cat = Jackson)