harman-04/spring-data-jpa-criteria-specifications
A demonstration of building dynamic, type-safe database queries using JPA Criteria API and Spring Data Specifications in Spring Boot 4.0.1.
Programmatic Querying: JPA Criteria API & Specifications
Project Overview
In real-world applications (like an e-commerce filter sidebar), the user might search by name, price, or both. Writing static HQL for every possible combination is impossible. This project uses the JPA Criteria API wrapped in Spring Data JPA Specifications to build these complex queries dynamically based on runtime conditions.
Technical Concepts
1. Criteria API Components
The Criteria API uses three main objects to construct a query:
- Root: The entity you are querying (e.g.,
Employee). It allows you to access class properties. - CriteriaQuery: The top-level query object where you define what to select (e.g.,
SELECT e). - CriteriaBuilder: The factory used to create "Predicates" (the
WHEREclause conditions likegreaterThanorlike).
2. Spring Data JPA Specifications
The raw Criteria API is very verbose. Spring Data's Specification interface simplifies this by allowing you to write reusable "blocks" of query logic that can be combined using and(), or(), and not().
3. Type-Safety
Unlike HQL or Native SQL, Specifications are built using Java code. If you rename a field in your entity, your IDE and compiler will immediately flag errors in your Specifications, making your codebase much easier to maintain and refactor.
Component Reference
EmployeeRepository.java
By extending JpaSpecificationExecutor<Employee>, the repository gains a new set of methods like findAll(Specification spec), which can accept the dynamic query logic we build.
EmployeeSpecifications.java
This is a utility class containing static factory methods.
hasSalaryGreaterThan: Creates a predicate for salary filtering.nameContains: Creates a predicate for partial name matching using the%wildcard.
CriteriaLearningRunner.java
This class demonstrates the "Lego-like" nature of Specifications:
Specification<Employee> spec = Specification
.where(EmployeeSpecifications.hasSalaryGreaterThan(50000))
.and(EmployeeSpecifications.nameContains("a"));Hibernate takes this object and dynamically generates a single SQL query:
SELECT * FROM employees WHERE salary > 50000 AND name LIKE '%a%';
Key Advantages
| Feature | Query Methods | HQL/JPQL | Criteria/Specs |
|---|---|---|---|
| Simplicity | High | Medium | Low |
| Dynamic Filters | Hard | Medium | High |
| Type Safety | Yes | No | Yes |
How to Test
- DB Setup: Ensure your MySQL database is active.
- Run: Start the
JpaCriteriaApiApplication. - Analyze Console:
- The application will first save 5 employees.
- It will then print only those who earn more than 50k AND have the letter 'a' in their name.
- Example Output:
--- Criteria API Filter Results ---
Raju Kumar - 60000.0
Syam - 85000.0
Output
Hibernate:
create table employees (
id bigint not null auto_increment,
name varchar(255),
salary float(53) not null,
primary key (id)
) engine=InnoDB
2026-01-18T23:06:32.976+05:30 INFO 18784 --- [jpa-criteria-api] [ restartedMain] j.LocalContainerEntityManagerFactoryBean : Initialized JPA EntityManagerFactory for persistence unit 'default'
2026-01-18T23:06:33.070+05:30 INFO 18784 --- [jpa-criteria-api] [ restartedMain] o.s.d.j.r.query.QueryEnhancerFactories : Hibernate is in classpath; If applicable, HQL parser will be used.
2026-01-18T23:06:33.216+05:30 WARN 18784 --- [jpa-criteria-api] [ restartedMain] JpaBaseConfiguration$JpaWebConfiguration : spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
2026-01-18T23:06:33.619+05:30 INFO 18784 --- [jpa-criteria-api] [ restartedMain] o.s.boot.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '/'
2026-01-18T23:06:33.627+05:30 INFO 18784 --- [jpa-criteria-api] [ restartedMain] c.j.JpaCriteriaApiApplication : Started JpaCriteriaApiApplication in 10.97 seconds (process running for 11.726)
Hibernate:
insert
into
employees
(name, salary)
values
(?, ?)
Hibernate:
insert
into
employees
(name, salary)
values
(?, ?)
Hibernate:
insert
into
employees
(name, salary)
values
(?, ?)
Hibernate:
insert
into
employees
(name, salary)
values
(?, ?)
Hibernate:
insert
into
employees
(name, salary)
values
(?, ?)
Hibernate:
select
e1_0.id,
e1_0.name,
e1_0.salary
from
employees e1_0
where
e1_0.salary>?
and e1_0.name like ? escape ''
--- Criteria API Filter Results ---
Raju Kumar-60000.0
Eswar-75000.0
Jagan-55000.0
Syam-85000.0