Criteria API

About

The Criteria API is a type-safe, object-oriented API in JPA used to create dynamic queries programmatically. Instead of writing queries as strings (like JPQL), it lets you build queries using Java objects and methods.

It was introduced in JPA 2.0 to address issues like:

  • Lack of compile-time checking in JPQL

  • Difficulty in building dynamic queries using string concatenation

Characteristics of Criteria API

Feature
Description

Type-Safe

Uses Java types; errors are caught at compile time.

Dynamic

You can build queries conditionally at runtime.

Object-Oriented

Constructs queries using objects, not string-based syntax.

Complex Query Support

Good for building queries with complex filters and conditions.

Integrated with EntityManager

Uses EntityManager to execute queries like JPQL.

Syntax Structure

Here’s how a typical Criteria API query looks:

// 1. Get CriteriaBuilder from EntityManager
CriteriaBuilder cb = entityManager.getCriteriaBuilder();

// 2. Create CriteriaQuery
CriteriaQuery<Employee> cq = cb.createQuery(Employee.class);

// 3. Define root entity
Root<Employee> root = cq.from(Employee.class);

// 4. Add predicates and select
cq.select(root).where(cb.equal(root.get("department"), "IT"));

// 5. Execute query
List<Employee> result = entityManager.createQuery(cq).getResultList();

Step 1: Get CriteriaBuilder from EntityManager

CriteriaBuilder is a factory object that helps create different parts of the query — like conditions (where), sorting (orderBy), grouping (groupBy), etc.

All Criteria queries start with a CriteriaBuilder. It provides methods like equal(), greaterThan(), and(), etc. — just like we would write in JPQL/SQL, but in an object-oriented way.

Step 2: Create CriteriaQuery

Creates the actual query object that will return Employee objects.

We must tell JPA what type of data we’re querying. This also sets the return type of your query.

Step 3: Define the Root Entity

Defines the main entity/table we're querying from — in SQL terms, this is like saying FROM employee.

It’s our main data source for the query. The root is what we use to access the entity fields like root.get("department").

Step 4: Add Select and Filter Conditions (Predicates)

  • cq.select(root): selects the entire Employee entity.

  • cb.equal(...): builds a condition where department = 'IT'.

  • .where(...): applies that condition to the query.

We are telling JPA

“I want all employees where department is 'IT'.”

We can also chain multiple conditions here using cb.and() or cb.or().

Step 5: Execute the Query

  • Converts the CriteriaQuery to an executable JPA query.

  • Runs it and fetches the result as a list of Employee objects.

This is where the query is actually run on the database, and you get your data back.

Final Output

After all the steps, result will hold something like:

Breakdown (like SQL)

Criteria API Equivalent
SQL Equivalent

cb.createQuery(Employee.class)

SELECT *

cq.from(Employee.class)

FROM Employee

cb.equal(root.get("department"), "IT")

WHERE department = 'IT'

Examples

Prerequisites

1. Basic SELECT

Fetch all employees.

2. SELECT with WHERE

Get employees in Sales department.

3. Using Multiple Conditions

IT employees with salary > 50,000.

4. Ordering

Order employees by salary descending.

5. Selecting Specific Fields (Projection)

Fetch employee names.

6. Joins

Our Employee entity has a field like

@ManyToOne private Department department;

Get employees in the Finance department.

7. Aggregate Functions

Get average salary.

8. Group By and Having

Departments with more than 5 employees.

  • multiselect(): Selects multiple values (in this case, the department and the count of employees).

  • groupBy(): Groups the results by department.

  • having(): Filters the grouped results, in this case to return only those departments with more than 5 employees.

9. Using IN Clause

Employees in IT, HR, or Finance.

10. Subqueries

Employees earning more than average salary.

Criteria API vs JPQL vs SQL

Feature
Criteria API
JPQL
SQL

Type-Safety

✅ Yes

❌ No

❌ No

Object-Oriented

✅ Yes

✅ Yes

❌ No

Complex Queries

✅ Yes

⚠️ Moderate

✅ Yes

Dynamic Building

✅ Best

❌ Hard

⚠️ Manual string concat

Compile-Time Check

✅ Yes

❌ No

❌ No

Portability

✅ High

✅ High

⚠️ DB-specific syntax

Learning Curve

⚠️ Steep

✅ Simple

⚠️ Moderate to Hard

Last updated