Anıl Şenocak Anıl Şenocak
Yazılım Mühendisi
Cover image
2026-07-11 0 toplam yorum
🚀 Building Dynamic Queries in Spring Boot with a Specification Builder

If you’ve ever written queries like then you already know the pain.

WHERE (:name IS NULL OR name LIKE %:name%)  
AND (:status IS NULL OR status = :status)  
AND (:date IS NULL OR created\_at > :date)

This is exactly where a Specification Builder approach shines.

In this article, we’ll explore how a Spring Boot Specification Builder project simplifies dynamic querying, eliminates boilerplate, and provides a clean, scalable architecture.

🧩 The Problem with Traditional Querying

Spring Data JPA offers multiple ways to query:

  • Derived query methods (findByNameAndStatus)
  • JPQL / Native queries
  • Criteria API
  • Specifications

Among these, Specifications stand out for dynamic querying because they allow you to build predicates programmatically.

However, raw Specifications come with their own problems:

  • Too much boilerplate
  • Hard to scale for complex filters
  • Repetitive predicate construction
  • Difficult to reuse

💡 The Idea Behind Specification Builder

The Specification Builder project introduces a generic, reusable, and extensible way to construct dynamic queries. Instead of writing custom specifications for every entity, it allows:

✅ Generic filtering
✅ Operator-based querying (EQUAL, LIKE, GREATER_THAN, etc.)
✅ Dynamic field selection
✅ Clean API request structure
✅ Reusable and composable logic

In short: you define filters → builder generates the query

✨ Why You'll Love It

1. 🔍 Deep Path Resolution (No More Join Nightmares)

One of the most tedious parts of JPA Specifications is managing joins for nested entities. The library handles this automatically using dot notation.

// This automatically creates all necessary LEFT JOINs for address and city  
Specification<User> spec = SpecBuilder.forClass(User.class)  
    .eq("address.city.name", "New York")  
    .build();

2. 🛡️ Built-in Null-Safety

Dynamic search forms often send null values for optional filters. Instead of wrapping every condition in an if (value != null) block, Easy Specification does it for you. If a value is null, the condition is simply skipped.

String email \= null; // This will be automatically ignored  
Specification<User> spec = SpecBuilder.forClass(User.class)  
    .eq("email", email)   
    .contains("name", "John")  
    .build();

3. 🛠️ Perfect for REST APIs

Building a dynamic search endpoint? You can easily map your incoming filters to the SpecBuilder.

@PostMapping("/search")  
public List<User> search(@RequestBody SearchRequest request) {  
    SpecBuilder<User> specBuilder = SpecBuilder.forClass(User.class);  
      
    for (FilterDto filter : request.filters()) {  
        // Map your dynamic filters here...  
        specBuilder.eq(filter.field(), filter.value());  
    }  
      
    return userRepository.findAll(specBuilder.build());  
}

📦 Getting Started

Installation

Add the dependency to your pom.xml:

<dependency>  
    <groupId>com.github.senocak.easyspec</groupId>
    <artifactId>spring-boot-easy-specification</artifactId>
    <version>1.0.1</version>
</dependency>

Or for Gradle:

implementation 'com.github.senocak.easyspec:spring-boot-easy-specification:1.0.1'

Quick Usage

import com.github.senocak.easyspec.builder.SpecBuilder;
import com.github.senocak.easyspec.builder.SpecBuilder;  
  
Specification<User> spec = SpecBuilder.forClass(User.class)  
    .eq("status", UserStatus.ACTIVE)  
    .orderBy("createdAt", Sort.Direction.DESC)  
    .build();  
  
List<User> users = userRepository.findAll(spec);

🛠️ Feature Overview

The SpecBuilder supports all the operations you'd expect:

  • Comparison: eq, ne, greaterThan, lessThan, gte, lte, between, in.
  • Null Checks: isNull, isNotNull.
  • String Matching: contains, startsWith, endsWith.
  • Sorting: orderBy.

github.com

Happy coding!

Yorumlar
Henüz yorum yok. İlk yorumu sen yaz.
Yorum Bırak
Adınız (isteğe bağlı)
Yorumunuzu yazın...
0/500