https://github.com/spring-projects/spring-boot/blob/ca0de4385c01cbbd120e96ec9f83427fb48c9a15/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/web/SpringDataWebAutoConfiguration.java#L54
Comment From: wilkinsona
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.
Comment From: jimlgx
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
Comment From: wilkinsona
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.
Comment From: jimlgx
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`
Comment From: wilkinsona
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.
Comment From: wilkinsona
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, if you are 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.
Comment From: wilkinsona
I've opened DATAREST-1290.
Comment From: RoonyLi
@Configuration
public class PageableConfig {
@Bean
PageableHandlerMethodArgumentResolverCustomizer pageableResolverCustomizer() {
return pageableResolver -> pageableResolver.setOneIndexedParameters(true);
}
}
it will work
Comment From: RoonyLi
i think the SpringDataWebAutoConfiguration should remove @ConditionalOnMissingBean(PageableHandlerMethodArgumentResolver.class) @wilkinsona
Comment From: 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).
Comment From: ghost
@All - Is this resolved ? What's the better alternative for this?
Comment From: wilkinsona
@JavaHelper We’ve done all we can in Boot by documenting Spring Data REST’s quirks. If this problem is important to you, please vote for or comment on DATAREST-1290 and let them know.
Comment From: zhangalex
@Configuration
public class PageableConfig {
@Bean
PageableHandlerMethodArgumentResolverCustomizer pageableResolverCustomizer() {
return pageableResolver -> pageableResolver.setOneIndexedParameters(true);
}
}
This is the best solution.
Comment From: wilkinsona
@gopalsingh462 If you are using Spring Data REST, that is to be expected. This is explained above:
They are then immediately overwritten based on the
RepositoryRestConfiguration.
Please follow this advice:
In short, if you are using Spring Data REST then you need to use the
spring.data.restproperties, if you are just using Spring Data's Web support without Spring Data REST, then you need to use thespring.data.web.pageableproperties. This isn't ideal, but is the best that we can do given Spring Data's current architecture.
Comment From: wilkinsona
I suspect you're not using Spring Data REST so you should set spring.data.web.pageable.one-indexed-parameters=true in your application.properties file.
If you have any further questions, please follow up on Stack Overflow or Gitter. As mentioned in the guidelines for contributing, we prefer to use GitHub issues only for bugs and enhancements.