Springfilter
Dynamically filter JPA entities, Mongo collections, and Java in-memory objects with a user-friendly query syntax. Seamless integration with Spring APIs. Star to support the project! ❤️
Install / Use
/learn @turkraft/SpringfilterREADME
Spring Filter
<p align="center"> <a href="https://github.com/turkraft/springfilter"> <img src="https://raw.githubusercontent.com/turkraft/springfilter/main/.github/logo.png?raw=true" alt="Spring Filter Logo"> </a> </p>Dynamic query filtering for Spring applications. Pass filter expressions as URL parameters and apply them to JPA repositories, MongoDB collections, or in-memory Java objects.
The library parses filter expressions into abstract syntax trees, then converts them to JPA Criteria queries, MongoDB queries, or Java Predicates depending on your module. You can also use the filter builder to construct queries programmatically.
<details> <summary>:warning: <b><u>About Release 3.0.0</u></b></summary>Spring Filter 3.0.0 is a new release built from the ground up. It includes much better integration with Spring, with many new features, enhancements and bug fixes. The language syntax didn't change, frontend applications will therefore not require any modification. The new
FilterBuilderclass is incompatible with the previous one and other breaking changes are present but the basic usage of the library remains similar. Please feel free to create an issue if you notice anything wrong. Consider supporting the project by sponsoring us.
</details>You can access the older version in the 2.x.x branch.
Example (try it live)
/search?filter= average(ratings) > 4.5 and brand.name in ['audi', 'land rover'] and (year > 2018 or km < 50000) and color : 'white' and accidents is empty
@Entity public class Car {
@Id long id;
int year;
int km;
@Enumerated Color color;
@ManyToOne Brand brand;
@OneToMany List<Accident> accidents;
@ElementCollection List<Integer> ratings;
}
The library handles booleans, dates, enums, functions, and entity relations. JPA module generates criteria queries, MongoDB module generates aggregation pipelines, and predicate module filters in-memory objects.
Sponsors
Sponsor our project and have your issues prioritized.
<table> <tr> <td><a href="https://github.com/ixorbv"><img width="64" src="https://avatars.githubusercontent.com/u/127401397?v=4"/></a></td> </tr> </table>Modules
JPA
Filter JPA entities directly in database queries. The module converts filter expressions to JPA Criteria API specifications.
<dependency>
<groupId>com.turkraft.springfilter</groupId>
<artifactId>jpa</artifactId>
<version>3.2.5</version>
</dependency>
@GetMapping("/cars")
Page<Car> search(@Filter Specification<Car> spec, Pageable page) {
return repository.findAll(spec, page);
}
The repository must implement JpaSpecificationExecutor. SimpleJpaRepository is a standard implementation. Remove the Pageable argument if you don't need pagination.
JPA with Native Queries
@GetMapping("/cars/native")
List<Car> searchNative(@Filter Specification<Car> spec) {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Car> query = cb.createQuery(Car.class);
Root<Car> root = query.from(Car.class);
query.where(spec.toPredicate(root, query, cb));
return entityManager.createQuery(query).getResultList();
}
JPA with Projections
@GetMapping("/cars/summary")
List<CarSummary> searchProjection(@Filter Specification<Car> spec) {
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<CarSummary> query = cb.createQuery(CarSummary.class);
Root<Car> root = query.from(Car.class);
query.select(cb.construct(CarSummary.class,
root.get("brand").get("name"),
cb.count(root)));
query.where(spec.toPredicate(root, query, cb));
query.groupBy(root.get("brand").get("name"));
return entityManager.createQuery(query).getResultList();
}
MongoDB
Filter MongoDB documents using Spring Data MongoDB queries.
<dependency>
<groupId>com.turkraft.springfilter</groupId>
<artifactId>mongo</artifactId>
<version>3.2.5</version>
</dependency>
@GetMapping("/cars")
Page<Car> search(@Filter(entityClass = Car.class) Query query, Pageable page) {
return mongoTemplate.find(query.with(page), Car.class);
}
With MongoRepository
public interface CarRepository extends MongoRepository<Car, String> {
@Query("?0")
List<Car> findAll(Document document);
@Query("?0")
Page<Car> findAll(Document document, Pageable pageable);
}
@GetMapping("/cars")
Page<Car> search(@Filter(entityClass = Car.class) Document document, Pageable page) {
return repository.findAll(document, page);
}
Predicate
Filter in-memory collections using Java Predicates. Works with any POJO, no database required.
<dependency>
<groupId>com.turkraft.springfilter</groupId>
<artifactId>predicate</artifactId>
<version>3.2.5</version>
</dependency>
@GetMapping("/cars")
List<Car> search(@Filter Predicate<Car> predicate) {
List<Car> allCars = loadCarsFromCache();
return allCars.stream()
.filter(predicate)
.collect(Collectors.toList());
}
Manual Conversion
@Autowired FilterPredicateConverter converter;
public List<Car> filterCars(List<Car> cars, String filterExpression) {
FilterPredicate<Car> predicate = converter.convert(filterExpression, Car.class);
return cars.stream()
.filter(predicate)
.collect(Collectors.toList());
}
Use Cases
The predicate module is useful when:
- Filtering cached data in memory
- Filtering API responses before returning to client
- Testing filter logic without database
- Filtering configuration objects or enums
- Processing batch data in memory
@GetMapping("/cars/cached")
List<Car> searchCached(@Filter Predicate<Car> predicate) {
return cacheService.getAllCars().stream()
.filter(predicate)
.collect(Collectors.toList());
}
@GetMapping("/cars/filter-after-fetch")
List<Car> filterAfterFetch(@Filter Predicate<Car> predicate) {
List<Car> cars = externalApiClient.fetchAllCars();
return cars.stream()
.filter(predicate)
.collect(Collectors.toList());
}
Size Function Support
// Filter by collection size
GET /cars?filter=size(accidents) > 2
GET /owners?filter=size(cars) : 0
The predicate module supports all standard operators and the size() function for collections, arrays, maps, and strings.
Filter Builder
Build filter expressions programmatically instead of writing filter strings manually.
<dependency>
<groupId>com.turkraft.springfilter</groupId>
<artifactId>core</artifactId>
<version>3.2.5</version>
</dependency>
@Autowired FilterBuilder fb;
FilterNode filter = fb.field("year").equal(fb.input(2025))
.and(fb.field("category").isNull())
.get();
@Autowired ConversionService cs;
String query = cs.convert(filter, String.class);
// year : 2025 and category is null
Complex Queries
FilterNode filter = fb.field("brand.name").in(
fb.collection(fb.input("audi"), fb.input("bmw"))
).and(
fb.field("year").greaterThan(fb.input(2020))
.or(fb.field("km").lessThan(fb.input(50000)))
).get();
With Functions
@Autowired SizeFunction sizeFunction;
FilterNode filter = fb.function(sizeFunction, fb.field("accidents"))
.greaterThan(fb.input(2))
.and(fb.field("year").lessThan(fb.input(2015)))
.get();
OpenAPI/Swagger
Add automatic Swagger documentation for endpoints with @Filter parameters.
<dependency>
<groupId>com.turkraft.springfilter</groupId>
<artifactId>openapi</artifactId>
<version>3.2.5</version>
</dependency>
Just add the dependency. Swagger UI automatically shows:
- All filterable fields with types
- Nested relations
- Enum values
- Example queries
- Operator reference
- Available functions
Works with JPA, MongoDB, and Predicate modules.
Pagination, Sorting and Field Selection
The page-sort module provides annotations for pagination, sorting, and field selection.
<dependency>
<groupId>com.turkraft.springfilter</groupId>
<artifactId>page-sort</artifactId>
<version>3.2.5</version>
</dependency>
Basic Usage
@GetMapping("/cars")
Page<Car> search(@Filter Specification<Car> spec, @Pagination Pageable page) {
return repository.findAll(spec, page);
}
Usage: ?page=0&size=20&sort=-year (prefix - for descending)
Custom Parameter Names
@GetMapping("/cars")
Page<Car> search(
@Pagination(pageParameter = "p", sizeParameter = "limit", sortParameter = "order") Pageable page) {
return repository.findAll(page);
}
Now use ?p=0&limit=50&order=-year
Sort Parameter
@GetMapping("/cars")
List<Car> search(@Sort org.springframework.data.domain.Sort sort) {
return repository.findAll(sort);
}
Use ?sort=-year or ?sort=-year,name
Field Selection
@Fields
@GetMapping("/cars")
List<Car> search() {
return repository.findAll();
}
Use ?fields=id,brand.name,year to return only specified fields. Uses Jackson's filtering internally.
// Include specific fields
?fields= id,name,email
// Exclude fields
?fields= *,-password,-ssn
// Nested fields
?fields= id,brand.name,brand.country
// Wildcards
?fields= user.*
Combined Example
@Fields
@GetMapping("/cars")
Page<Car> search(
@Filter Specification<Car> spec,
@Pagination Pageable page) {
return repository.findAll(spec, page);
}
Use all features together:
/cars?filter=year>2020&page=0&size=20&sort=-year&fields=id,brand.name,year
The openapi module automatically genera
Related Skills
openhue
339.5kControl Philips Hue lights and scenes via the OpenHue CLI.
sag
339.5kElevenLabs text-to-speech with mac-style say UX.
weather
339.5kGet current weather and forecasts via wttr.in or Open-Meteo
tweakcc
1.5kCustomize Claude Code's system prompts, create custom toolsets, input pattern highlighters, themes/thinking verbs/spinners, customize input box & user message styling, support AGENTS.md, unlock private/unreleased features, and much more. Supports both native/npm installs on all platforms.
