From 1c42faf8138c803eddc3caee9406ca5c19c1a01b Mon Sep 17 00:00:00 2001 From: "Greg L. Turnquist" Date: Wed, 11 May 2022 16:38:53 -0500 Subject: [PATCH] Extend query method special parameter types to any subclasses. Spring Data Commons has a hard-coded list of special types than can be included in query methods including Pageable and Sort. A custom finder with PageRequest, even though it extends Pageable, will fail when it would work fine with a narrowed input. This extends the list using an assignability check. Related: spring-projects/spring-data-jpa#2013 See #2626. --- .../data/repository/query/Parameter.java | 23 +++++++++++++++++-- .../ParametersParameterAccessorUnitTests.java | 16 +++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/springframework/data/repository/query/Parameter.java b/src/main/java/org/springframework/data/repository/query/Parameter.java index e05dcde6e..32186e74e 100644 --- a/src/main/java/org/springframework/data/repository/query/Parameter.java +++ b/src/main/java/org/springframework/data/repository/query/Parameter.java @@ -42,6 +42,7 @@ import org.springframework.util.Assert; * @author Oliver Gierke * @author Mark Paluch * @author Jens Schauder + * @author Greg Turnquist */ public class Parameter { @@ -79,7 +80,7 @@ public class Parameter { this.parameter = parameter; this.parameterType = potentiallyUnwrapParameterType(parameter); this.isDynamicProjectionParameter = isDynamicProjectionParameter(parameter); - this.name = TYPES.contains(parameter.getParameterType()) ? Lazy.of(Optional.empty()) : Lazy.of(() -> { + this.name = isSpecialParameterType(parameter.getParameterType()) ? Lazy.of(Optional.empty()) : Lazy.of(() -> { Param annotation = parameter.getParameterAnnotation(Param.class); return Optional.ofNullable(annotation == null ? parameter.getParameterName() : annotation.value()); }); @@ -92,7 +93,7 @@ public class Parameter { * @see #TYPES */ public boolean isSpecialParameter() { - return isDynamicProjectionParameter || TYPES.contains(parameter.getParameterType()); + return isDynamicProjectionParameter || isSpecialParameterType(parameter.getParameterType()); } /** @@ -273,4 +274,22 @@ public class Parameter { return originalType; } + + /** + * Identify is a given {@link Class} is either part of {@code TYPES} or an instanceof of one of its members. For + * example, {@code PageRequest} is an instance of {@code Pageable} (a member of {@code TYPES}). + * + * @param parameterType must not be {@literal null}. + * @return boolean + */ + private static boolean isSpecialParameterType(Class parameterType) { + + for (Class specialParameterType : TYPES) { + if (specialParameterType.isAssignableFrom(parameterType)) { + return true; + } + } + + return false; + } } diff --git a/src/test/java/org/springframework/data/repository/query/ParametersParameterAccessorUnitTests.java b/src/test/java/org/springframework/data/repository/query/ParametersParameterAccessorUnitTests.java index e655b72a6..9c37ccce4 100755 --- a/src/test/java/org/springframework/data/repository/query/ParametersParameterAccessorUnitTests.java +++ b/src/test/java/org/springframework/data/repository/query/ParametersParameterAccessorUnitTests.java @@ -29,6 +29,7 @@ import org.springframework.data.domain.Pageable; * Unit tests for {@link ParametersParameterAccessor}. * * @author Oliver Gierke + * @author Greg Turnquist */ class ParametersParameterAccessorUnitTests { @@ -75,6 +76,19 @@ class ParametersParameterAccessorUnitTests { new Object[] { PageRequest.of(0, 10), "Foo" }); assertThat(accessor).hasSize(1); + assertThat(accessor.getBindableValue(0)).isEqualTo("Foo"); + } + + @Test // #2626 + void handlesPageRequestAsAParameterType() throws NoSuchMethodException { + + Method method = Sample.class.getMethod("methodWithPageRequest", PageRequest.class, String.class); + DefaultParameters parameters = new DefaultParameters(method); + + ParameterAccessor accessor = new ParametersParameterAccessor(parameters, new Object[] { PageRequest.of(0, 10), "Foo" }); + + assertThat(accessor).hasSize(1); + assertThat(accessor.getBindableValue(0)).isEqualTo("Foo"); } interface Sample { @@ -82,5 +96,7 @@ class ParametersParameterAccessorUnitTests { void method(String string, int integer); void method(Pageable pageable, String string); + + void methodWithPageRequest(PageRequest pageRequest, String string); } }