diff --git a/src/main/java/org/springframework/data/web/OptionalPageableHandlerMethodArgumentResolver.java b/src/main/java/org/springframework/data/web/OptionalPageableHandlerMethodArgumentResolver.java new file mode 100644 index 0000000000..163439575d --- /dev/null +++ b/src/main/java/org/springframework/data/web/OptionalPageableHandlerMethodArgumentResolver.java @@ -0,0 +1,56 @@ +/* + * Copyright 2013-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.web; + +import org.springframework.core.MethodParameter; +import org.springframework.data.domain.Pageable; +import org.springframework.lang.Nullable; +import org.springframework.web.bind.support.WebDataBinderFactory; +import org.springframework.web.context.request.NativeWebRequest; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.method.support.ModelAndViewContainer; + +import java.util.Optional; + +/** + * Optional wrapper resolver for {@link PageableHandlerMethodArgumentResolver}. + * + * @author Yanming Zhou + */ +public class OptionalPageableHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver { + + private final PageableHandlerMethodArgumentResolver pageableHandlerMethodArgumentResolver; + + /** + * Constructs an instance of this resolver with the specified {@link PageableHandlerMethodArgumentResolver}. + * + * @param pageableHandlerMethodArgumentResolver the pageable resolver to use + */ + public OptionalPageableHandlerMethodArgumentResolver(PageableHandlerMethodArgumentResolver pageableHandlerMethodArgumentResolver) { + this.pageableHandlerMethodArgumentResolver = pageableHandlerMethodArgumentResolver; + } + + @Override + public boolean supportsParameter(MethodParameter parameter) { + return Optional.class == parameter.getParameterType() && Pageable.class == parameter.nested().getParameterType(); + } + + @Override + public Optional resolveArgument(MethodParameter methodParameter, @Nullable ModelAndViewContainer mavContainer, + NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) { + return Optional.of(pageableHandlerMethodArgumentResolver.resolveArgument(methodParameter, mavContainer, webRequest, binderFactory)); + } +} diff --git a/src/main/java/org/springframework/data/web/config/SpringDataWebConfiguration.java b/src/main/java/org/springframework/data/web/config/SpringDataWebConfiguration.java index 383ceee7e4..22e03eebf7 100644 --- a/src/main/java/org/springframework/data/web/config/SpringDataWebConfiguration.java +++ b/src/main/java/org/springframework/data/web/config/SpringDataWebConfiguration.java @@ -29,6 +29,7 @@ import org.springframework.data.repository.support.DomainClassConverter; import org.springframework.data.util.Lazy; import org.springframework.data.web.OffsetScrollPositionHandlerMethodArgumentResolver; +import org.springframework.data.web.OptionalPageableHandlerMethodArgumentResolver; import org.springframework.data.web.PageableHandlerMethodArgumentResolver; import org.springframework.data.web.ProjectingJackson2HttpMessageConverter; import org.springframework.data.web.ProxyingHandlerMethodArgumentResolver; @@ -96,6 +97,12 @@ public void setBeanClassLoader(ClassLoader classLoader) { this.beanClassLoader = classLoader; } + @Bean + public OptionalPageableHandlerMethodArgumentResolver optionalPageableResolver() { + + return new OptionalPageableHandlerMethodArgumentResolver(pageableResolver.get()); + } + @Bean public PageableHandlerMethodArgumentResolver pageableResolver() { diff --git a/src/test/java/org/springframework/data/web/OptionalPageableHandlerMethodArgumentResolverUnitTests.java b/src/test/java/org/springframework/data/web/OptionalPageableHandlerMethodArgumentResolverUnitTests.java new file mode 100755 index 0000000000..a493449185 --- /dev/null +++ b/src/test/java/org/springframework/data/web/OptionalPageableHandlerMethodArgumentResolverUnitTests.java @@ -0,0 +1,54 @@ +/* + * Copyright 2013-2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.data.web; + +import org.junit.jupiter.api.Test; +import org.springframework.core.MethodParameter; +import org.springframework.data.domain.Pageable; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.web.context.request.ServletWebRequest; + +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Unit tests for {@link OptionalPageableHandlerMethodArgumentResolver}. + * + * @author Yanming Zhou + */ +class OptionalPageableHandlerMethodArgumentResolverUnitTests { + + @Test + void optionalWrapperOfPageable() throws Exception { + + OptionalPageableHandlerMethodArgumentResolver resolver = new OptionalPageableHandlerMethodArgumentResolver(new PageableHandlerMethodArgumentResolver()); + + MethodParameter methodParameter = new MethodParameter(Sample.class.getMethod("supportedMethod", Optional.class), 0); + var request = new MockHttpServletRequest(); + request.addParameter("page", "0"); + request.addParameter("size", "23"); + + Optional pageable = resolver.resolveArgument(methodParameter, null, new ServletWebRequest(request), null); + assertThat(pageable).isPresent().get().extracting(Pageable::getPageSize).isEqualTo(23); + } + + interface Sample { + + void supportedMethod(Optional pageable); + + } +} diff --git a/src/test/java/org/springframework/data/web/config/EnableSpringDataWebSupportIntegrationTests.java b/src/test/java/org/springframework/data/web/config/EnableSpringDataWebSupportIntegrationTests.java index 10c8909b3d..b0d3bd95a4 100755 --- a/src/test/java/org/springframework/data/web/config/EnableSpringDataWebSupportIntegrationTests.java +++ b/src/test/java/org/springframework/data/web/config/EnableSpringDataWebSupportIntegrationTests.java @@ -150,7 +150,7 @@ void registersBasicBeanDefinitions() { ApplicationContext context = WebTestUtils.createApplicationContext(SampleConfig.class); var names = Arrays.asList(context.getBeanDefinitionNames()); - assertThat(names).contains("pageableResolver", "sortResolver"); + assertThat(names).contains("optionalPageableResolver", "pageableResolver", "sortResolver"); assertResolversRegistered(context, SortHandlerMethodArgumentResolver.class, PageableHandlerMethodArgumentResolver.class);