Reputation: 21978
I'm using org.springframework.data.domain.Pageable with my @RestController
.
How can I validate or limit the page size?
Without any validation, when clients call with size
of 10000
. The actual pageSize
is 2000
.
This could lead wrong signal for last page, I think.
How can I validate it and notify clients about it? Say with 400
?
Upvotes: 8
Views: 6312
Reputation: 67
You can simply use configuration
spring.data.web.pageable.max-page-size=400
This will not lead to any error if one tries to get 401 records. Only 400 will be returned. More on stuff that can be configured via spring properties could be found here:
https://docs.spring.io/spring-boot/docs/current/reference/html/appendix-application-properties.html
Upvotes: 1
Reputation: 131
You can write a custom annotation to validate Pageable
object
@Constraint(validatedBy = PageableValidator.class)
@Target( { ElementType.METHOD, ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
public @interface PageableConstraint {
String message() default "Invalid pagination";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
int maxPerPage() default 100;;
}
and Its implementation
public class PageableValidator implements
ConstraintValidator<PageableConstraint, Pageable> {
private int maxPerPage;
@Override
public void initialize(PageableConstraint constraintAnnotation) {
maxPerPage=constraintAnnotation.maxPerPage();
}
@Override
public boolean isValid(Pageable value, ConstraintValidatorContext context) {
return value.getPageSize()<=maxPerPage;
}
}
and you can use it over your controller like any other javax validation annotations.
@RestController
@RequestMapping("/api")
@Validated
public class EmployeeRestController {
@Autowired
private EmployeeService employeeService;
@GetMapping("/employees")
public List<Employee> getAllEmployees(@PageableConstraint(message = "Invalid page size",maxPerPage = 400) Pageable pageable) {
return employeeService.getAllEmployees();
}
}
Upvotes: 7
Reputation: 1472
Try using Custom Annotations to validate the Pageable object. If it is not working, try the argument resolver as shown below.
You can create Argument Resolver in your Spring Configuration that is extending WebMvcConfigurerAdapter
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
PageableHandlerMethodArgumentResolver resolver = new PageableHandlerMethodArgumentResolver() {
@Override
public Pageable resolveArgument(MethodParameter methodParameter, ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, WebDataBinderFactory binderFactory) {
Pageable p = super.resolveArgument(methodParameter, mavContainer, webRequest, binderFactory);
if (webRequest.getParameter("per_page") != null) {
int pageSize = Integer.parseInt(webRequest.getParameter("per_page"));
if (pageSize < 1 || pageSize > 2000) {
message = "Invalid page size";
}
}
if (message != null) {
Set<CustomConstraintViolation> constraintViolations = new HashSet<>();
constraintViolations.add(new CustomConstraintViolationImpl(message));
throw new ConstraintViolationException(constraintViolations);
}
return new PageRequest(p.getPageNumber(), p.getPageSize());
}
};
resolver.setMaxPageSize(2000);
argumentResolvers.add(resolver);
super.addArgumentResolvers(argumentResolvers);
}
This resolver will make sure the max page size is 2000 for every request to your controller.
You need to throw a ConstraintViolationException when the size is more than 2000. For that you need to create a custom ConstraintViolation interface and implement it
public CustomConstraintViolation implements ConstraintViolation<CustomConstraintViolation> {}
public CustomConstraintViolationImpl implements CustomConstraintViolation {
...
}
Upvotes: 1