Careeroza
Criteria API
Building Queries in Java Code
JPQL strings are fixed. A search page with optional filters (category, min price, max price, in stock, text) would need dozens of query variants. The Criteria API builds the query step by step in Java, adding only the filters the user actually set.
public List<Product> search(ProductFilter f) {
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Product> cq = cb.createQuery(Product.class);
Root<Product> p = cq.from(Product.class);
List<Predicate> where = new ArrayList<>();
if (f.category() != null) where.add(cb.equal(p.get("category").get("name"), f.category()));
if (f.minPrice() != null) where.add(cb.greaterThanOrEqualTo(p.get("price"), f.minPrice()));
if (f.maxPrice() != null) where.add(cb.lessThanOrEqualTo(p.get("price"), f.maxPrice()));
if (f.inStockOnly()) where.add(cb.greaterThan(p.get("stock"), 0));
if (f.text() != null) where.add(cb.like(cb.lower(p.get("name")), "%" + f.text().toLowerCase() + "%"));
cq.select(p).where(where.toArray(Predicate[]::new)).orderBy(cb.asc(p.get("price")));
return em.createQuery(cq).getResultList();
}
public record ProductFilter(String category, BigDecimal minPrice, BigDecimal maxPrice,
boolean inStockOnly, String text) {}SQL for Two Different Filter Sets
Example
search(new ProductFilter("Electronics", null, new BigDecimal("2000"), true, null));
search(new ProductFilter(null, null, null, false, "kurta"));Example output
DEBUG org.hibernate.SQL : select p1_0.id,p1_0.category_id,p1_0.description,p1_0.name,p1_0.price,p1_0.stock from products p1_0 join categories c1_0 on c1_0.id=p1_0.category_id where c1_0.name=? and p1_0.price<=? and p1_0.stock>? order by p1_0.price DEBUG org.hibernate.SQL : select p1_0.id,p1_0.category_id,p1_0.description,p1_0.name,p1_0.price,p1_0.stock from products p1_0 where lower(p1_0.name) like ? escape '' order by p1_0.price
Type-safe Metamodel
p.get("price") uses a string; a typo fails only at runtime. The JPA static metamodel generates a class Product_ with typed attributes at compile time.
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-jpamodelgen</artifactId> <!-- named hibernate-processor from Hibernate 6.5 -->
<scope>provided</scope>
</dependency>where.add(cb.lessThanOrEqualTo(p.get(Product_.price), f.maxPrice())); // compile-time checked
where.add(cb.equal(p.get(Product_.category).get(Category_.name), f.category()));