Thanks for the report, but I'm not sure that your analysis is correct. The PageableHandlerMethodArgumentResolverCustomizer is consumed by org.springframework.data.web.config.SpringDataWebConfiguration which is imported via @EnableSpringDataWebConfiguration with which SpringDataWebAutoConfiguration is annotated. I'm not sure that RepositoryRestMvcAutoConfiguration is relevant. I may be wrong, of course.
It sounds like the problem you're facing is that configuration of spring.data.web.pageable isn't working. Can you please provide a minimal sample that reproduces that problem? That will allow us to figure out exactly what the cause is and be confident that we're fixing the problem that you're having.
I found it through debugging,In SpringDataWebConfiguration that
private @Autowired Optional<PageableHandlerMethodArgumentResolverCustomizer> pageableResolverCustomizer;
the value is null,No injection succeeds,I can write a unit test later
I can write a unit test later
Thanks. Either a unit test or a small sample that reproduces the problem will give us what we need to make some progress on this one.
Referring to the demo you provided _public void customizePageable() I have modified it
Please refer to the unit tests below to illustrate the problem and hopefully help you
@RunWith(SpringRunner.class)
@SpringBootTest
@EnableConfigurationProperties(value = {SpringDataWebProperties.class})
public class SpringDataWebTest {
@Autowired
private ApplicationContext context;
@Autowired
private SpringDataWebProperties properties;
@Test
public void customizePageableWithConfig() {
PageableHandlerMethodArgumentResolver argumentResolver = this.context
.getBean(PageableHandlerMethodArgumentResolver.class);
// properties.pageable equal to properties config
assertThat(properties.getPageable().getPageParameter())
.isEqualTo("p");
assertThat(properties.getPageable().getSizeParameter())
.isEqualTo("s");
assertThat(properties.getPageable().isOneIndexedParameters())
.isEqualTo(true);
assertThat(properties.getPageable().getPrefix())
.isEqualTo("abc");
assertThat(properties.getPageable().getQualifierDelimiter())
.isEqualTo("__");
assertThat(properties.getPageable().getMaxPageSize())
.isEqualTo(100);
// properties.pageable not equal argumentResolver
assertThat(ReflectionTestUtils.getField(argumentResolver, "pageParameterName"))
.isNotEqualTo(properties.getPageable().getPageParameter());
assertThat(ReflectionTestUtils.getField(argumentResolver, "sizeParameterName"))
.isNotEqualTo(properties.getPageable().getSizeParameter());
assertThat(ReflectionTestUtils.getField(argumentResolver, "oneIndexedParameters"))
.isNotEqualTo(properties.getPageable().isOneIndexedParameters());
assertThat(ReflectionTestUtils.getField(argumentResolver, "prefix"))
.isNotEqualTo(properties.getPageable().getPrefix());
assertThat(ReflectionTestUtils.getField(argumentResolver, "qualifierDelimiter"))
.isNotEqualTo(properties.getPageable().getQualifierDelimiter());
assertThat(ReflectionTestUtils.getField(argumentResolver, "maxPageSize"))
.isNotEqualTo(properties.getPageable().getMaxPageSize());
}
spring.data.web.pageable.page-parameter=p
spring.data.web.pageable.size-parameter=s
spring.data.web.pageable.default-page-size=10
spring.data.web.pageable.prefix=abc
spring.data.web.pageable.qualifier-delimiter=__
spring.data.web.pageable.max-page-size=100
spring.data.web.pageable.one-indexed-parameters=true`
https://github.com/jimlgx/spring-boot-demo/blob/master/src/test/java/com/example/springbootdemo/SpringDataWebTest.java
Thanks again. I can see the problem now. It is indeed due to some interaction between RespositoryRestMvcAutoConfiguration and SpringDataWebAutoConfiguration but the solution isn't as simple as reversing their ordering.
Our current test passes as it tests SpringDataWebAutoConfiguration in isolation. It's testing a scenario where Spring Data REST isn't on the classpath. If Spring Data REST is on the classpath, then RespositoryRestMvcAutoConfiguration comes into play. When it goes before SpringDataWebAutoConfiguration, SpringDataWebAutoConfiguration backs off due to it being conditional on a missing PageableHandlerMethodArgumentResolver which is defined by RepositoryRestMvcConfiguration (an import of RespositoryRestMvcAutoConfiguration). This backing off means that the beans that customise both paging and sorting are lost. I believe we also lose some other functionality that's imported via @EnableSpringDataWebSupport. If the order is reversed and SpringDataWebAutoConfiguration goes first then several beans are overridden causing a failure on master where bean overriding is no longer permitted.
When SpringDataWebAutoConfiguration backs off, we lose its @EnableSpringDataWebSupport in favour of an import of RepositoryRestMvcConfiguration. RepositoryRestMvcConfiguration is a subclass of HateoasAwareSpringDataWebConfiguration which is some of what @EnableSpringDataWebSupport imports. It's not yet clear to me how to fix this such that the customisation of both paging and sorting is retained while also retaining all of the functionality enabled by @EnableSpringDataWebSupport.
It isn't possible to fix this in Spring Boot due to the way in which Spring Data is structured.
If you're using Spring Data REST, then org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration.pageableResolver() is the method that will create the PageableHandlerMethodArgumentResolver. It calls its super method to create and customise the resolver using a PageableHandlerMethodArgumentResolverCustomizer which applies the spring.data.web.pageable properties. They are then immediately overwritten based on the RepositoryRestConfiguration. In Spring Boot, RepositoryRestConfiguration can be customised using the spring.data.rest properties.
In short, if you are using Spring Data REST then you need to use the spring.data.rest properties, it you just using Spring Data's Web support without Spring Data REST, then you need to use the spring.data.web.pageable properties. This isn't ideal, but is the best that we can do given Spring Data's current architecture.
I think we should open a Spring Data issue and turn this into a documentation issue.
I've opened DATAREST-1290.
@Configuration
public class PageableConfig {
@Bean
PageableHandlerMethodArgumentResolverCustomizer pageableResolverCustomizer() {
return pageableResolver -> pageableResolver.setOneIndexedParameters(true);
}
}
it will work
i think the SpringDataWebAutoConfiguration should remove @ConditionalOnMissingBean(PageableHandlerMethodArgumentResolver.class) @wilkinsona
Thanks for the suggestion but we can't do that as it may result in multiple PageableHandlerMethodArgumentResolverCustomizer beans and Spring Data requires there to be at most one (or for one to be @Primary).
@All - Is this resolved ? What's the better alternative for this?
@JavaHelper We鈥檝e done all we can in Boot by documenting Spring Data REST鈥檚 quirks. If this problem is important to you, please vote for or comment on DATAREST-1290 and let them know.
@Configuration
public class PageableConfig {
@Bean
PageableHandlerMethodArgumentResolverCustomizer pageableResolverCustomizer() {
return pageableResolver -> pageableResolver.setOneIndexedParameters(true);
}
}
This is the best solution.
Most helpful comment
it will work