diff --git a/docs/src/main/asciidoc/spring-cloud-openfeign.adoc b/docs/src/main/asciidoc/spring-cloud-openfeign.adoc index 1858b0e3..5a4d9944 100644 --- a/docs/src/main/asciidoc/spring-cloud-openfeign.adoc +++ b/docs/src/main/asciidoc/spring-cloud-openfeign.adoc @@ -758,17 +758,15 @@ In the following example, the `CSV` format is used instead of the default `EXPLO [source,java,indent=0] ---- @FeignClient(name = "demo") -protected interface PageableFeignClient { +protected interface DemoFeignClient { @CollectionFormat(feign.CollectionFormat.CSV) - @GetMapping(path = "/page") - ResponseEntity performRequest(Pageable page); + @GetMapping(path = "/test") + ResponseEntity performRequest(String test); } ---- -TIP: Set the `CSV` format while sending `Pageable` as a query parameter in order for it to be encoded correctly. - === Reactive Support As the https://github.com/OpenFeign/feign[OpenFeign project] does not currently support reactive clients, such as https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/reactive/function/client/WebClient.html[Spring WebClient], neither does Spring Cloud OpenFeign.We will add support for it here as soon as it becomes available in the core project. diff --git a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/SpringMvcContract.java b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/SpringMvcContract.java index 98e52e56..430bb44c 100644 --- a/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/SpringMvcContract.java +++ b/spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/support/SpringMvcContract.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 the original author or authors. + * Copyright 2013-2023 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. @@ -60,6 +60,7 @@ import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.ResourceLoader; +import org.springframework.data.domain.Pageable; import org.springframework.http.InvalidMediaTypeException; import org.springframework.http.MediaType; import org.springframework.util.Assert; @@ -265,6 +266,16 @@ public class SpringMvcContract extends Contract.BaseContract implements Resource protected boolean processAnnotationsOnParameter(MethodMetadata data, Annotation[] annotations, int paramIndex) { boolean isHttpAnnotation = false; + try { + if (Pageable.class.isAssignableFrom(data.method().getParameterTypes()[paramIndex])) { + data.queryMapIndex(paramIndex); + return false; + } + } + catch (NoClassDefFoundError ignored) { + // Do nothing; added to avoid exceptions if optional dependency not present + } + AnnotatedParameterProcessor.AnnotatedParameterContext context = new SimpleAnnotatedParameterContext(data, paramIndex); Method method = processedMethods.get(data.configKey()); diff --git a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/support/SpringMvcContractTests.java b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/support/SpringMvcContractTests.java index f789bfa7..919e85c8 100644 --- a/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/support/SpringMvcContractTests.java +++ b/spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/support/SpringMvcContractTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2013-2022 the original author or authors. + * Copyright 2013-2023 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. @@ -37,6 +37,8 @@ import org.junit.jupiter.api.Test; import org.springframework.cloud.openfeign.CollectionFormat; import org.springframework.cloud.openfeign.SpringQueryMap; import org.springframework.core.convert.ConversionService; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.format.annotation.DateTimeFormat; import org.springframework.format.annotation.NumberFormat; import org.springframework.format.number.NumberStyleFormatter; @@ -625,6 +627,16 @@ class SpringMvcContractTests { .isEqualTo("cookie1={cookie1}; cookie2={cookie2}"); } + @Test + void shouldNotFailWhenBothPageableAndRequestBodyParamsInPostRequest() { + List data = contract.parseAndValidateMetadata(TestTemplate_PageablePost.class); + + assertThat(data.get(0).queryMapIndex().intValue()).isEqualTo(0); + assertThat(data.get(0).bodyIndex().intValue()).isEqualTo(1); + assertThat(data.get(1).queryMapIndex().intValue()).isEqualTo(1); + assertThat(data.get(1).bodyIndex().intValue()).isEqualTo(0); + } + private ConversionService getConversionService() { FormattingConversionServiceFactoryBean conversionServiceFactoryBean = new FormattingConversionServiceFactoryBean(); conversionServiceFactoryBean.afterPropertiesSet(); @@ -826,6 +838,16 @@ class SpringMvcContractTests { } + public interface TestTemplate_PageablePost { + + @PostMapping + Page getPage(Pageable pageable, @RequestBody String body); + + @PostMapping + Page getPage(@RequestBody String body, Pageable pageable); + + } + @JsonAutoDetect(fieldVisibility = ANY, getterVisibility = NONE, setterVisibility = NONE) public class TestObject {