Skip to content

Commit 8e9b11f

Browse files
committed
Fix pageable processing when querymap present. (#843)
1 parent 23ca17d commit 8e9b11f

File tree

2 files changed

+49
-8
lines changed

2 files changed

+49
-8
lines changed

spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/SpringMvcContract.java

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,14 @@
3434
import feign.Feign;
3535
import feign.MethodMetadata;
3636
import feign.Param;
37+
import feign.QueryMap;
3738
import feign.Request;
3839
import org.apache.commons.logging.Log;
3940
import org.apache.commons.logging.LogFactory;
4041

4142
import org.springframework.cloud.openfeign.AnnotatedParameterProcessor;
4243
import org.springframework.cloud.openfeign.CollectionFormat;
44+
import org.springframework.cloud.openfeign.SpringQueryMap;
4345
import org.springframework.cloud.openfeign.annotation.CookieValueParameterProcessor;
4446
import org.springframework.cloud.openfeign.annotation.MatrixVariableParameterProcessor;
4547
import org.springframework.cloud.openfeign.annotation.PathVariableParameterProcessor;
@@ -67,6 +69,7 @@
6769
import org.springframework.util.StringUtils;
6870
import org.springframework.web.bind.annotation.RequestMapping;
6971
import org.springframework.web.bind.annotation.RequestMethod;
72+
import org.springframework.web.bind.annotation.RequestParam;
7073

7174
import static feign.Util.checkState;
7275
import static feign.Util.emptyToNull;
@@ -158,7 +161,7 @@ private static TypeDescriptor createTypeDescriptor(Method method, int paramIndex
158161

159162
private static TypeDescriptor getElementTypeDescriptor(TypeDescriptor typeDescriptor) {
160163
TypeDescriptor elementTypeDescriptor = typeDescriptor.getElementTypeDescriptor();
161-
// that means it's not a collection but it is iterable, gh-135
164+
// that means it's not a collection, but it is iterable, gh-135
162165
if (elementTypeDescriptor == null && Iterable.class.isAssignableFrom(typeDescriptor.getType())) {
163166
ResolvableType type = typeDescriptor.getResolvableType().as(Iterable.class).getGeneric(0);
164167
if (type.resolve() == null) {
@@ -268,8 +271,12 @@ protected boolean processAnnotationsOnParameter(MethodMetadata data, Annotation[
268271

269272
try {
270273
if (Pageable.class.isAssignableFrom(data.method().getParameterTypes()[paramIndex])) {
271-
data.queryMapIndex(paramIndex);
272-
return false;
274+
// do not set a Pageable as QueryMap if there's an actual QueryMap param
275+
// present
276+
if (!queryMapParamPresent(data)) {
277+
data.queryMapIndex(paramIndex);
278+
return false;
279+
}
273280
}
274281
}
275282
catch (NoClassDefFoundError ignored) {
@@ -304,6 +311,20 @@ protected boolean processAnnotationsOnParameter(MethodMetadata data, Annotation[
304311
return isHttpAnnotation;
305312
}
306313

314+
private boolean queryMapParamPresent(MethodMetadata data) {
315+
Annotation[][] paramsAnnotations = data.method().getParameterAnnotations();
316+
for (int i = 0; i < paramsAnnotations.length; i++) {
317+
Annotation[] paramAnnotations = paramsAnnotations[i];
318+
Class<?> parameterType = data.method().getParameterTypes()[i];
319+
if (Arrays.stream(paramAnnotations).anyMatch(
320+
annotation -> Map.class.isAssignableFrom(parameterType) && annotation instanceof RequestParam
321+
|| annotation instanceof SpringQueryMap || annotation instanceof QueryMap)) {
322+
return true;
323+
}
324+
}
325+
return false;
326+
}
327+
307328
private void parseProduces(MethodMetadata md, Method method, RequestMapping annotation) {
308329
String[] serverProduces = annotation.produces();
309330
String clientAccepts = serverProduces.length == 0 ? null : emptyToNull(serverProduces[0]);

spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/support/SpringMvcContractTests.java

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -631,10 +631,20 @@ void testMultipleCookiesAnnotation() throws NoSuchMethodException {
631631
void shouldNotFailWhenBothPageableAndRequestBodyParamsInPostRequest() {
632632
List<MethodMetadata> data = contract.parseAndValidateMetadata(TestTemplate_PageablePost.class);
633633

634-
assertThat(data.get(0).queryMapIndex().intValue()).isEqualTo(0);
635-
assertThat(data.get(0).bodyIndex().intValue()).isEqualTo(1);
636-
assertThat(data.get(1).queryMapIndex().intValue()).isEqualTo(1);
637-
assertThat(data.get(1).bodyIndex().intValue()).isEqualTo(0);
634+
assertThat(data.get(0).queryMapIndex()).isEqualTo(0);
635+
assertThat(data.get(0).bodyIndex()).isEqualTo(1);
636+
assertThat(data.get(1).queryMapIndex()).isEqualTo(1);
637+
assertThat(data.get(1).bodyIndex()).isEqualTo(0);
638+
}
639+
640+
@Test
641+
void shouldSetPageableAsBodyWhenQueryMapParamPresent() {
642+
List<MethodMetadata> data = contract.parseAndValidateMetadata(TestTemplate_PageablePostWithQueryMap.class);
643+
644+
assertThat(data.get(0).queryMapIndex()).isEqualTo(0);
645+
assertThat(data.get(0).bodyIndex()).isEqualTo(1);
646+
assertThat(data.get(1).queryMapIndex()).isEqualTo(1);
647+
assertThat(data.get(1).bodyIndex()).isEqualTo(0);
638648
}
639649

640650
private ConversionService getConversionService() {
@@ -838,7 +848,7 @@ public interface TestTemplate_NumberFormatParameter {
838848

839849
}
840850

841-
public interface TestTemplate_PageablePost {
851+
interface TestTemplate_PageablePost {
842852

843853
@PostMapping
844854
Page<String> getPage(Pageable pageable, @RequestBody String body);
@@ -848,6 +858,16 @@ public interface TestTemplate_PageablePost {
848858

849859
}
850860

861+
interface TestTemplate_PageablePostWithQueryMap {
862+
863+
@PostMapping
864+
Page<String> getPage(@SpringQueryMap TestObject pojo, Pageable pageable);
865+
866+
@PostMapping
867+
Page<String> getPage(Pageable pageable, @SpringQueryMap TestObject pojo);
868+
869+
}
870+
851871
@JsonAutoDetect(fieldVisibility = ANY, getterVisibility = NONE, setterVisibility = NONE)
852872
public class TestObject {
853873

0 commit comments

Comments
 (0)