Specifications

Basic Spring
≈ 2 min read

Dynamic search from small conditions

Imagine a search screen where the user can independently specify status, name, minimum age, and other filters. Creating a separate repository method for every combination quickly becomes inconvenient. For such cases, Spring Data JPA provides a Specification — an object that describes one query condition.

interface CustomerRepository
        extends JpaRepository<Customer, Long>,
                JpaSpecificationExecutor<Customer> {
}

Specification<Customer> active =
        (root, query, cb) -> cb.isTrue(root.get("active"));

Specification<Customer> adult =
        (root, query, cb) -> cb.greaterThanOrEqualTo(root.get("age"), 18);

List<Customer> customers = repository.findAll(active.and(adult));

Each specification describes a small predicate. The JpaSpecificationExecutor interface adds methods that can execute such conditions, and specifications can be combined with and, or, and negation.

When Specifications are especially useful

They work well for filters whose set is determined at runtime: for example, some fields in a search form may be filled in while others are empty. The code can add only the required conditions and then pass the resulting combination to the repository.

Specification is built on the Criteria API. That is why the code works with the entity model and JPA criteria objects instead of an SQL string. For a simple fixed query, a derived query or @Query is usually easier to read.