Overview
Spring Data Web Spec is an open-source library for annotation-based mapping from web requests (query parameters, headers, path variables, and security context) to Spring Data JPA Specifications.
- Declare filters directly in controller method parameters
- Integrates seamlessly with Spring MVC and Spring Data JPA
- Extensible operator model (
Equal
,In
,ContainsIgnoreCase
,IsNull
, etc.) - Built-in access control support via
@Spec.AccessControl
for security-based filters - Minimal runtime dependencies
- Spring Boot autoconfiguration and optional
@EnableWebSpec
annotation for easy setup
👉 Source code is available on GitHub.
Installation
Maven
<dependency>
<groupId>com.cariochi.spec</groupId>
<artifactId>spring-data-web-spec</artifactId>
<version>1.0.2</version>
</dependency>
Quick start
Configuration
You can register the argument resolver in one of two ways:
1. Spring Boot autoconfiguration (recommended)
If you use Spring Boot 3.x and have spring-data-web-spec on the classpath, the SpecArgumentResolver
will be auto-registered.
Autoconfiguration is enabled by default but can be disabled via:
cariochi.spec.web.enabled=false
2. Manual registration via @EnableWebSpec
If you don’t want to rely on autoconfiguration (or you use plain Spring MVC without Boot), annotate your configuration class:
@EnableWebSpec
@Configuration
public class WebConfig {
}
Example Usage
@RestController
@RequiredArgsConstructor
class DummyController {
private final DummyService service;
private final DummyMapper mapper;
@GetMapping("/organizations/{organizationId}/dummy")
public Page<DummyDto> findAll(
@Spec.PathVariable(name = "organizationId", path = "organization.id", required = true)
@Spec.RequestParam(name = "id")
@Spec.RequestParam(name = "status", operator = In.class)
@Spec.RequestParam(name = "name", operator = ContainsIgnoreCase.class)
@Spec.RequestParam(name = "propertyValue", path = "properties.value", joinType = JoinType.INNER, operator = In.class, distinct = true)
@Spec.RequestHeader(name = "region", path = "organization.region")
@Spec.AccessControl(path = "organization.region", valueSupplier = UserAllowedRegions.class, operator = In.class)
Specification<DummyEntity> specification,
Pageable pageable
) {
return service.findAll(specification, pageable)
.map(mapper::toDto);
}
}
How it works
-
Annotate a
Specification<T>
method parameter with one or more source annotations:@Spec.RequestParam
— query parameter@Spec.RequestHeader
— HTTP header@Spec.PathVariable
— URI path variable@Spec.AccessControl
— security-based, no request value needed
-
SpecArgumentResolver
:- Reads the values from the HTTP request or security context.
- Converts them using Spring’s ConversionService.
- Passes them to the chosen operator.
-
An operator implements:
interface SpecOperator<T, Y, V> { Specification<T> buildSpecification(SpecContext<T, Y, V> ctx); }
-
All generated specifications are combined with AND logic.
Built-in operators
- Equal, NotEqual
- In, NotIn
- Contains, ContainsIgnoreCase
- StartWith, StartWithIgnoreCase
- IsNull, IsNotNull
- GreaterThan, GreaterThanOrEqualTo, LessThan, LessThanOrEqualTo
You can also implement custom operators.
Access control / security
Use @Spec.AccessControl
for filters without request input, e.g., enforcing user-specific restrictions.
Example:
Value Supplier can be a Supplier<List<String>>
that returns the allowed regions for the current user:
@Component
@RequiredArgsConstructor
class UserAllowedRegions implements Supplier<List<String>> {
private final UserService userService;
@Override
public List<String> get() {
return userService.getUserAllowedRegions();
}
}
Usage example:
@Spec.AccessControl(
path = "organization.region",
valueSupplier = UserAllowedRegions.class,
operator = In.class
)
This will automatically restrict queries to allowed regions for the current user.
License
The library is distributed under the Apache License, Version 2.0.