From 31598b4329d63a12ae4f8b5825988b6553a9fb42 Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Tue, 14 Jun 2016 10:37:04 +0200 Subject: [PATCH 1/8] Bumped up version of commons to snapshot --- spring-cloud-netflix-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-cloud-netflix-dependencies/pom.xml b/spring-cloud-netflix-dependencies/pom.xml index 17ec3655..404a9620 100644 --- a/spring-cloud-netflix-dependencies/pom.xml +++ b/spring-cloud-netflix-dependencies/pom.xml @@ -14,7 +14,7 @@ spring-cloud-netflix-dependencies Spring Cloud Netflix Dependencies - 1.1.1.RELEASE + 1.1.2.BUILD-SNAPSHOT 1.1.1.RELEASE 1.0.2.RELEASE 0.7.4 From 8b0598abee646735f24d552f360f8e8a6bfad40e Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Tue, 14 Jun 2016 10:50:21 +0200 Subject: [PATCH 2/8] Bumped up version of cloud-config to snapshot --- spring-cloud-netflix-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-cloud-netflix-dependencies/pom.xml b/spring-cloud-netflix-dependencies/pom.xml index 404a9620..91c9e4a9 100644 --- a/spring-cloud-netflix-dependencies/pom.xml +++ b/spring-cloud-netflix-dependencies/pom.xml @@ -15,7 +15,7 @@ Spring Cloud Netflix Dependencies 1.1.2.BUILD-SNAPSHOT - 1.1.1.RELEASE + 1.1.2.BUILD-SNAPSHOT 1.0.2.RELEASE 0.7.4 1.4.8 From ccc75f29787159285c6f2d403c76b3ca4e173cc2 Mon Sep 17 00:00:00 2001 From: Marcin Grzejszczak Date: Tue, 14 Jun 2016 11:24:48 +0200 Subject: [PATCH 3/8] Bumped up version of cloud-stream to snapshot --- spring-cloud-netflix-dependencies/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-cloud-netflix-dependencies/pom.xml b/spring-cloud-netflix-dependencies/pom.xml index 91c9e4a9..19f91221 100644 --- a/spring-cloud-netflix-dependencies/pom.xml +++ b/spring-cloud-netflix-dependencies/pom.xml @@ -16,7 +16,7 @@ 1.1.2.BUILD-SNAPSHOT 1.1.2.BUILD-SNAPSHOT - 1.0.2.RELEASE + 1.0.3.BUILD-SNAPSHOT 0.7.4 1.4.8 8.16.2 From e819dd39ca28f10c6df206978bf135e94cb1e124 Mon Sep 17 00:00:00 2001 From: Spencer Gibb Date: Wed, 15 Jun 2016 17:09:14 -0600 Subject: [PATCH 4/8] Only install and skip javadoc generation --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 042c01f5..fe1e1d04 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,10 +14,10 @@ before_install: - echo "https://$GH_TOKEN:@github.com" > .git/credentials - gem install asciidoctor install: -- ./mvnw install -P docs -q -U -DskipTests=true -Dmaven.test.redirectTestOutputToFile=true +- ./mvnw install -P docs -q -U -DskipTests=true -Dmaven.test.redirectTestOutputToFile=true -Dmaven.javadoc.skip=true - '[ "${MVN_GOAL}" == "deploy" ] && ./docs/src/main/asciidoc/ghpages.sh || echo "Not updating docs"' script: -- './mvnw -s .settings.xml $MVN_GOAL $MVN_PROFILE -nsu -Dmaven.test.redirectTestOutputToFile=true' +- './mvnw -s .settings.xml $MVN_GOAL $MVN_PROFILE -nsu -Dmaven.javadoc.skip=true -Dmaven.test.redirectTestOutputToFile=true' env: global: - GIT_NAME="Dave Syer" @@ -25,7 +25,7 @@ env: - CI_DEPLOY_USERNAME=buildmaster - FEATURE_BRANCH=$(echo ${TRAVIS_BRANCH} | grep -q "^.*/.*$" && echo true || echo false) - SPRING_CLOUD_BUILD=$(echo ${TRAVIS_REPO_SLUG} | grep -q "^spring-cloud/.*$" && echo true || echo false) - - MVN_GOAL=$([ "${TRAVIS_PULL_REQUEST}" == "false" -a "${TRAVIS_TAG}" == "" -a "${FEATURE_BRANCH}" == "false" -a "${SPRING_CLOUD_BUILD}" == "true" ] && echo deploy || echo install) + - MVN_GOAL=install - VERSION=$(mvn validate | grep Building | head -1 | sed -e 's/.* //') - MILESTONE=$(echo ${VERSION} | egrep 'M|RC' && echo true || echo false) - MVN_PROFILE=$([ "${MILESTONE}" == "true" ] && echo -P milestone) From 88ce4fe81b6de192644c7e0bb4f64f5bd5b8929a Mon Sep 17 00:00:00 2001 From: Spencer Gibb Date: Wed, 15 Jun 2016 17:16:12 -0600 Subject: [PATCH 5/8] skip source generation --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index fe1e1d04..4f7f03c1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,12 +14,13 @@ before_install: - echo "https://$GH_TOKEN:@github.com" > .git/credentials - gem install asciidoctor install: -- ./mvnw install -P docs -q -U -DskipTests=true -Dmaven.test.redirectTestOutputToFile=true -Dmaven.javadoc.skip=true +- ./mvnw install -P docs -q -U -DskipTests=true $MVN_LOCAL_OPTS - '[ "${MVN_GOAL}" == "deploy" ] && ./docs/src/main/asciidoc/ghpages.sh || echo "Not updating docs"' script: -- './mvnw -s .settings.xml $MVN_GOAL $MVN_PROFILE -nsu -Dmaven.javadoc.skip=true -Dmaven.test.redirectTestOutputToFile=true' +- './mvnw -s .settings.xml $MVN_GOAL $MVN_PROFILE -nsu $MVN_LOCAL_OPTS' env: global: + - MVN_LOCAL_OPTS=-Dmaven.source.skip=true -Dmaven.javadoc.skip=true -Dmaven.test.redirectTestOutputToFile=true - GIT_NAME="Dave Syer" - GIT_EMAIL=dsyer@pivotal.io - CI_DEPLOY_USERNAME=buildmaster From 050c66250c3dcffd542c1228202d9ad61c58dfd5 Mon Sep 17 00:00:00 2001 From: Spencer Gibb Date: Wed, 15 Jun 2016 17:17:52 -0600 Subject: [PATCH 6/8] quote var --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4f7f03c1..53b5304b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,7 +20,7 @@ script: - './mvnw -s .settings.xml $MVN_GOAL $MVN_PROFILE -nsu $MVN_LOCAL_OPTS' env: global: - - MVN_LOCAL_OPTS=-Dmaven.source.skip=true -Dmaven.javadoc.skip=true -Dmaven.test.redirectTestOutputToFile=true + - MVN_LOCAL_OPTS="-Dmaven.source.skip=true -Dmaven.javadoc.skip=true -Dmaven.test.redirectTestOutputToFile=true" - GIT_NAME="Dave Syer" - GIT_EMAIL=dsyer@pivotal.io - CI_DEPLOY_USERNAME=buildmaster From 20db8685928077f4950adcf194149028bc42d030 Mon Sep 17 00:00:00 2001 From: Spencer Gibb Date: Thu, 16 Jun 2016 11:45:52 -0600 Subject: [PATCH 7/8] Don't send 4xx errors to /error fixes gh-1110 --- .../filters/route/RibbonRoutingFilter.java | 9 ------- .../route/SimpleHostRoutingFilter.java | 8 ------ .../zuul/SampleZuulProxyApplicationTests.java | 6 +++-- .../cloud/netflix/zuul/ZuulProxyTestBase.java | 25 ++++++++++++++----- 4 files changed, 23 insertions(+), 25 deletions(-) diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/RibbonRoutingFilter.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/RibbonRoutingFilter.java index 3903822b..02305106 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/RibbonRoutingFilter.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/RibbonRoutingFilter.java @@ -78,7 +78,6 @@ public class RibbonRoutingFilter extends ZuulFilter { RibbonCommandContext commandContext = buildCommandContext(context); ClientHttpResponse response = forward(commandContext); setResponse(response); - setErrorCodeFor4xx(context, response); return response; } catch (ZuulException ex) { @@ -94,14 +93,6 @@ public class RibbonRoutingFilter extends ZuulFilter { return null; } - private void setErrorCodeFor4xx(RequestContext context, ClientHttpResponse response) - throws IOException { - HttpStatus httpStatus = response.getStatusCode(); - if (httpStatus.is4xxClientError()) { - context.set(ERROR_STATUS_CODE, httpStatus.value()); - } - } - protected RibbonCommandContext buildCommandContext(RequestContext context) { HttpServletRequest request = context.getRequest(); diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/SimpleHostRoutingFilter.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/SimpleHostRoutingFilter.java index ae1d3f43..4b8e9020 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/SimpleHostRoutingFilter.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/route/SimpleHostRoutingFilter.java @@ -175,7 +175,6 @@ public class SimpleHostRoutingFilter extends ZuulFilter { HttpResponse response = forward(this.httpClient, verb, uri, request, headers, params, requestEntity); setResponse(response); - setErrorCodeFor4xx(context, response); } catch (Exception ex) { context.set(ERROR_STATUS_CODE, @@ -185,13 +184,6 @@ public class SimpleHostRoutingFilter extends ZuulFilter { return null; } - private void setErrorCodeFor4xx(RequestContext context, HttpResponse response) { - HttpStatus httpStatus = HttpStatus.valueOf(response.getStatusLine().getStatusCode()); - if (httpStatus.is4xxClientError()) { - context.set(ERROR_STATUS_CODE, httpStatus.value()); - } - } - protected PoolingHttpClientConnectionManager newConnectionManager() { try { final SSLContext sslContext = SSLContext.getInstance("SSL"); diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/SampleZuulProxyApplicationTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/SampleZuulProxyApplicationTests.java index 35eb1281..dc5bb9ee 100644 --- a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/SampleZuulProxyApplicationTests.java +++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/SampleZuulProxyApplicationTests.java @@ -113,11 +113,13 @@ public class SampleZuulProxyApplicationTests extends ZuulProxyTestBase { public void simpleHostRouteWithNonExistentUrl() { this.routes.addRoute("/self/**", "http://localhost:" + this.port + "/"); this.endpoint.reset(); + String uri = "/self/nonExistentUrl"; + this.myErrorController.setUriToMatch(uri); ResponseEntity result = new TestRestTemplate().exchange( - "http://localhost:" + this.port + "/self/nonExistentUrl", HttpMethod.GET, + "http://localhost:" + this.port + uri, HttpMethod.GET, new HttpEntity<>((Void) null), String.class); assertEquals(HttpStatus.NOT_FOUND, result.getStatusCode()); - assertTrue(this.myErrorController.wasControllerUsed()); + assertFalse(this.myErrorController.wasControllerUsed()); } @Test diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/ZuulProxyTestBase.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/ZuulProxyTestBase.java index 33fc36bc..85afec6b 100644 --- a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/ZuulProxyTestBase.java +++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/zuul/ZuulProxyTestBase.java @@ -43,7 +43,6 @@ import com.netflix.zuul.context.RequestContext; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; /** * @author Spencer Gibb @@ -155,8 +154,10 @@ public abstract class ZuulProxyTestBase { @Test public void ribbonRouteWithSpace() { + String uri = "/simple/spa ce"; + this.myErrorController.setUriToMatch(uri); ResponseEntity result = new TestRestTemplate().exchange( - "http://localhost:" + this.port + "/simple/spa ce", HttpMethod.GET, + "http://localhost:" + this.port + uri, HttpMethod.GET, new HttpEntity<>((Void) null), String.class); assertEquals(HttpStatus.OK, result.getStatusCode()); assertEquals("Hello space", result.getBody()); @@ -165,11 +166,13 @@ public abstract class ZuulProxyTestBase { @Test public void ribbonRouteWithNonExistentUri() { + String uri = "/simple/nonExistent"; + this.myErrorController.setUriToMatch(uri); ResponseEntity result = new TestRestTemplate().exchange( - "http://localhost:" + this.port + "/simple/nonExistent", HttpMethod.GET, + "http://localhost:" + this.port + uri, HttpMethod.GET, new HttpEntity<>((Void) null), String.class); assertEquals(HttpStatus.NOT_FOUND, result.getStatusCode()); - assertTrue(myErrorController.wasControllerUsed()); + assertFalse(myErrorController.wasControllerUsed()); } @Test @@ -325,6 +328,7 @@ class AnotherRibbonClientConfiguration { } class MyErrorController extends BasicErrorController { + ThreadLocal uriToMatch = new ThreadLocal<>(); AtomicBoolean controllerUsed = new AtomicBoolean(); @@ -334,10 +338,19 @@ class MyErrorController extends BasicErrorController { @Override public ResponseEntity> error(HttpServletRequest request) { - controllerUsed.set(true); + String errorUri = (String) request.getAttribute("javax.servlet.error.request_uri"); + + if (errorUri != null && errorUri.equals(this.uriToMatch.get())) { + controllerUsed.set(true); + } + this.uriToMatch.remove(); return super.error(request); } + public void setUriToMatch(String uri) { + this.uriToMatch.set(uri); + } + public boolean wasControllerUsed() { return this.controllerUsed.get(); } @@ -345,4 +358,4 @@ class MyErrorController extends BasicErrorController { public void clear() { this.controllerUsed.set(false); } -} \ No newline at end of file +} From 9e479481ccccfad60007d1ccecd959ce5fc2bd4f Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Fri, 17 Jun 2016 14:55:35 +0100 Subject: [PATCH 8/8] Exempt @RequestParams of type Collection from feign expander It isn't very helpful to have a Collection converted to a String anyway. We need to implement something new in Feign to apply the converter (expander) to individual elements in the collection but this change should get back to the old behaviour with List at least. Fixes gh-1115 --- .../RequestParamParameterProcessor.java | 40 +++++++------- .../feign/support/SpringMvcContract.java | 16 ++++-- .../feign/support/SpringEncoderTests.java | 32 +++++++----- .../feign/support/SpringMvcContractTests.java | 52 +++++++++++++------ 4 files changed, 90 insertions(+), 50 deletions(-) diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/annotation/RequestParamParameterProcessor.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/annotation/RequestParamParameterProcessor.java index edd2b226..a67da38b 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/annotation/RequestParamParameterProcessor.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/annotation/RequestParamParameterProcessor.java @@ -22,11 +22,11 @@ import java.util.Collection; import org.springframework.cloud.netflix.feign.AnnotatedParameterProcessor; import org.springframework.web.bind.annotation.RequestParam; -import feign.MethodMetadata; - import static feign.Util.checkState; import static feign.Util.emptyToNull; +import feign.MethodMetadata; + /** * {@link RequestParam} parameter processor. * @@ -35,23 +35,27 @@ import static feign.Util.emptyToNull; */ public class RequestParamParameterProcessor implements AnnotatedParameterProcessor { - private static final Class ANNOTATION = RequestParam.class; + private static final Class ANNOTATION = RequestParam.class; - @Override - public Class getAnnotationType() { - return ANNOTATION; - } + @Override + public Class getAnnotationType() { + return ANNOTATION; + } - @Override - public boolean processArgument(AnnotatedParameterContext context, Annotation annotation) { - String name = ANNOTATION.cast(annotation).value(); - checkState(emptyToNull(name) != null, - "RequestParam.value() was empty on parameter %s", context.getParameterIndex()); - context.setParameterName(name); + @Override + public boolean processArgument(AnnotatedParameterContext context, + Annotation annotation) { + RequestParam requestParam = ANNOTATION.cast(annotation); + String name = requestParam.value(); + checkState(emptyToNull(name) != null, + "RequestParam.value() was empty on parameter %s", + context.getParameterIndex()); + context.setParameterName(name); - MethodMetadata data = context.getMethodMetadata(); - Collection query = context.setTemplateParameter(name, data.template().queries().get(name)); - data.template().query(name, query); - return true; - } + MethodMetadata data = context.getMethodMetadata(); + Collection query = context.setTemplateParameter(name, + data.template().queries().get(name)); + data.template().query(name, query); + return true; + } } diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/support/SpringMvcContract.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/support/SpringMvcContract.java index 7dab129c..34b1a643 100644 --- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/support/SpringMvcContract.java +++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/support/SpringMvcContract.java @@ -45,15 +45,15 @@ import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; +import static feign.Util.checkState; +import static feign.Util.emptyToNull; +import static org.springframework.core.annotation.AnnotatedElementUtils.findMergedAnnotation; + import feign.Contract; import feign.Feign; import feign.MethodMetadata; import feign.Param; -import static feign.Util.checkState; -import static feign.Util.emptyToNull; -import static org.springframework.core.annotation.AnnotatedElementUtils.findMergedAnnotation; - /** * @author Spencer Gibb */ @@ -237,6 +237,7 @@ public class SpringMvcContract extends Contract.BaseContract } } if (isHttpAnnotation && data.indexToExpander().get(paramIndex) == null + && !isMultiValued(method.getParameterTypes()[paramIndex]) && this.conversionService.canConvert( method.getParameterTypes()[paramIndex], String.class)) { data.indexToExpander().put(paramIndex, this.expander); @@ -244,6 +245,13 @@ public class SpringMvcContract extends Contract.BaseContract return isHttpAnnotation; } + private boolean isMultiValued(Class type) { + // Feign will deal with each element in a collection individually (with no + // expander as of 8.16.2, but we'd rather have no conversion than convert a + // collection to a String (which ends up being a csv). + return Collection.class.isAssignableFrom(type); + } + private void parseProduces(MethodMetadata md, Method method, RequestMapping annotation) { checkAtMostOne(method, annotation.produces(), "produces"); diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/support/SpringEncoderTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/support/SpringEncoderTests.java index a101e691..cfa04cac 100644 --- a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/support/SpringEncoderTests.java +++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/support/SpringEncoderTests.java @@ -27,13 +27,13 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.test.context.web.WebAppConfiguration; import org.springframework.web.bind.annotation.RestController; -import feign.RequestTemplate; -import lombok.Data; - import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; import static org.junit.Assert.assertThat; +import feign.RequestTemplate; +import lombok.Data; + /** * @author Spencer Gibb */ @@ -50,7 +50,7 @@ public class SpringEncoderTests { @Autowired @Qualifier("myHttpMessageConverter") - private HttpMessageConverter myConverter; + private HttpMessageConverter myConverter; @Test public void testCustomHttpMessageConverter() { @@ -73,14 +73,14 @@ public class SpringEncoderTests { private MediaType mediaType; public MediaTypeMatcher(String type, String subtype) { - mediaType = new MediaType(type, subtype); + this.mediaType = new MediaType(type, subtype); } @Override public boolean matches(Object argument) { if (argument instanceof MediaType) { MediaType other = (MediaType) argument; - return mediaType.equals(other); + return this.mediaType.equals(other); } return false; } @@ -88,7 +88,7 @@ public class SpringEncoderTests { @Override public String toString() { final StringBuffer sb = new StringBuffer("MediaTypeMatcher{"); - sb.append("mediaType=").append(mediaType); + sb.append("mediaType=").append(this.mediaType); sb.append('}'); return sb.toString(); } @@ -109,18 +109,19 @@ public class SpringEncoderTests { protected static class Application implements TestClient { @Bean - HttpMessageConverter myHttpMessageConverter() { + HttpMessageConverter myHttpMessageConverter() { return new MyHttpMessageConverter(); } - private static class MyHttpMessageConverter extends AbstractGenericHttpMessageConverter { + private static class MyHttpMessageConverter + extends AbstractGenericHttpMessageConverter { public MyHttpMessageConverter() { super(new MediaType("application", "mytype")); } @Override - protected boolean supports(Class clazz) { + protected boolean supports(Class clazz) { return false; } @@ -135,17 +136,22 @@ public class SpringEncoderTests { } @Override - protected void writeInternal(Object o, Type type, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { + protected void writeInternal(Object o, Type type, + HttpOutputMessage outputMessage) + throws IOException, HttpMessageNotWritableException { } @Override - protected Object readInternal(Class clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { + protected Object readInternal(Class clazz, HttpInputMessage inputMessage) + throws IOException, HttpMessageNotReadableException { return null; } @Override - public Object read(Type type, Class contextClass, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { + public Object read(Type type, Class contextClass, + HttpInputMessage inputMessage) + throws IOException, HttpMessageNotReadableException { return null; } } diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/support/SpringMvcContractTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/support/SpringMvcContractTests.java index 1cf2a3fd..a6616361 100644 --- a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/support/SpringMvcContractTests.java +++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/support/SpringMvcContractTests.java @@ -18,6 +18,7 @@ package org.springframework.cloud.netflix.feign.support; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.List; import org.junit.Before; import org.junit.Test; @@ -34,14 +35,16 @@ import org.springframework.web.bind.annotation.RequestParam; import com.fasterxml.jackson.annotation.JsonAutoDetect; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assume.assumeTrue; + import feign.MethodMetadata; import lombok.AllArgsConstructor; import lombok.NoArgsConstructor; import lombok.ToString; -import static org.junit.Assert.assertEquals; -import static org.junit.Assume.assumeTrue; - /** * @author chadjaros */ @@ -97,10 +100,10 @@ public class SpringMvcContractTests { @Test public void testProcessAnnotations_Class_AnnotationsGetSpecificTest() throws Exception { - Method method = TestTemplate_Class_Annotations.class.getDeclaredMethod( - "getSpecificTest", String.class, String.class); - MethodMetadata data = this.contract.parseAndValidateMetadata( - method.getDeclaringClass(), method); + Method method = TestTemplate_Class_Annotations.class + .getDeclaredMethod("getSpecificTest", String.class, String.class); + MethodMetadata data = this.contract + .parseAndValidateMetadata(method.getDeclaringClass(), method); assertEquals("/prepend/{classId}/test/{testId}", data.template().url()); assertEquals("GET", data.template().method()); @@ -111,10 +114,10 @@ public class SpringMvcContractTests { @Test public void testProcessAnnotations_Class_AnnotationsGetAllTests() throws Exception { - Method method = TestTemplate_Class_Annotations.class.getDeclaredMethod( - "getAllTests", String.class); - MethodMetadata data = this.contract.parseAndValidateMetadata( - method.getDeclaringClass(), method); + Method method = TestTemplate_Class_Annotations.class + .getDeclaredMethod("getAllTests", String.class); + MethodMetadata data = this.contract + .parseAndValidateMetadata(method.getDeclaringClass(), method); assertEquals("/prepend/{classId}", data.template().url()); assertEquals("GET", data.template().method()); @@ -129,10 +132,10 @@ public class SpringMvcContractTests { MethodMetadata extendedData = this.contract.parseAndValidateMetadata( extendedMethod.getDeclaringClass(), extendedMethod); - Method method = TestTemplate_Class_Annotations.class.getDeclaredMethod( - "getAllTests", String.class); - MethodMetadata data = this.contract.parseAndValidateMetadata( - method.getDeclaringClass(), method); + Method method = TestTemplate_Class_Annotations.class + .getDeclaredMethod("getAllTests", String.class); + MethodMetadata data = this.contract + .parseAndValidateMetadata(method.getDeclaringClass(), method); assertEquals(extendedData.template().url(), data.template().url()); assertEquals(extendedData.template().method(), data.template().method()); @@ -193,6 +196,7 @@ public class SpringMvcContractTests { assertEquals("Authorization", data.indexToName().get(0).iterator().next()); assertEquals("id", data.indexToName().get(1).iterator().next()); assertEquals("amount", data.indexToName().get(2).iterator().next()); + assertNotNull(data.indexToExpander().get(2)); assertEquals("{Authorization}", data.template().headers().get("Authorization").iterator().next()); @@ -245,6 +249,19 @@ public class SpringMvcContractTests { data.template().headers().get("Accept").iterator().next()); } + @Test + public void testProcessAnnotations_ListParams() throws Exception { + Method method = TestTemplate_ListParams.class.getDeclaredMethod("getTest", + List.class); + MethodMetadata data = this.contract + .parseAndValidateMetadata(method.getDeclaringClass(), method); + + assertEquals("/test", data.template().url()); + assertEquals("GET", data.template().method()); + assertEquals("[{id}]", data.template().queries().get("id").toString()); + assertNull(data.indexToExpander().get(0)); + } + @Test public void testProcessHeaders() throws Exception { Method method = TestTemplate_Headers.class.getDeclaredMethod("getTest", @@ -339,6 +356,11 @@ public class SpringMvcContractTests { ResponseEntity getTest(@PathVariable("id") String id); } + public interface TestTemplate_ListParams { + @RequestMapping(value = "/test", method = RequestMethod.GET) + ResponseEntity getTest(@RequestParam("id") List id); + } + @JsonAutoDetect @RequestMapping("/advanced") public interface TestTemplate_Advanced {