From 2c502e3997eaca84eb8c4198fa6f3bd45cf49bba Mon Sep 17 00:00:00 2001 From: Jacques-Etienne Beaudet Date: Wed, 11 May 2016 20:17:55 -0400 Subject: [PATCH] Add support in SpringMvcContract for query string in Class @RequestMapping This commit adds the support for query string defined in the class' @RequestMapping Annotation that is applied to all method of a controller. Fxies gh-1023, fixes gh-1024 --- .../feign/support/SpringMvcContract.java | 33 ++++++++------ .../feign/support/SpringMvcContractTests.java | 43 +++++++++++++------ 2 files changed, 51 insertions(+), 25 deletions(-) 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 0e8a2824..4c4113c4 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 @@ -106,6 +106,26 @@ public class SpringMvcContract extends Contract.BaseContract this.resourceLoader = resourceLoader; } + @Override + protected void processAnnotationOnClass(MethodMetadata data, Class clz) { + if(clz.getInterfaces().length == 0) { + RequestMapping classAnnotation = findMergedAnnotation(clz, + RequestMapping.class); + if (classAnnotation != null) { + // Prepend path from class annotation if specified + if (classAnnotation.value().length > 0) { + String pathValue = emptyToNull(classAnnotation.value()[0]); + pathValue = resolve(pathValue); + if (!pathValue.startsWith("/")) { + pathValue = "/" + pathValue; + } + data.template().insert(0, pathValue); + } + } + } + } + + @Override public MethodMetadata parseAndValidateMetadata(Class targetType, Method method) { this.processedMethods.put(Feign.configKey(targetType, method), method); @@ -114,19 +134,6 @@ public class SpringMvcContract extends Contract.BaseContract RequestMapping classAnnotation = findMergedAnnotation(targetType, RequestMapping.class); if (classAnnotation != null) { - // Prepend path from class annotation if specified - if (classAnnotation.value().length > 0) { - String pathValue = emptyToNull(classAnnotation.value()[0]); - checkState(pathValue != null, - "RequestMapping.value() was empty on type %s", - method.getDeclaringClass().getName()); - pathValue = resolve(pathValue); - if (!pathValue.startsWith("/")) { - pathValue = "/" + pathValue; - } - md.template().insert(0, pathValue); - } - // produces - use from class annotation only if method has not specified this if (!md.template().headers().containsKey(ACCEPT)) { parseProduces(md, method, classAnnotation); 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 bf91e535..26363910 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 @@ -72,39 +72,51 @@ public class SpringMvcContractTests { String.class); MethodMetadata data = this.contract .parseAndValidateMetadata(method.getDeclaringClass(), method); + MethodMetadata extendingData = this.contract + .parseAndValidateMetadata(method.getDeclaringClass(), method); - assertEquals("/test/{id}", data.template().url()); + assertEquals("/prepend/{anotherId}", data.template().url()); + assertEquals(data.template().url(), extendingData.template().url()); assertEquals("GET", data.template().method()); + assertEquals(data.template().method(), extendingData.template().method()); assertEquals(MediaType.APPLICATION_JSON_VALUE, data.template().headers().get("Accept").iterator().next()); + assertEquals(data.template().headers().get("Accept").iterator().next(), + extendingData.template().headers().get("Accept").iterator().next()); + + assertEquals("anotherId", data.indexToName().get(0).iterator().next()); + assertEquals(data.indexToName().get(0).iterator().next(), + extendingData.indexToName().get(0).iterator().next()); } - + @Test public void testProcessAnnotations_Simple() throws Exception { Method method = TestTemplate_Simple.class.getDeclaredMethod("getTest", - String.class); + String.class, String.class); MethodMetadata data = this.contract .parseAndValidateMetadata(method.getDeclaringClass(), method); - assertEquals("/test/{id}", data.template().url()); + assertEquals("/prepend/{anotherId}/test/{id}", data.template().url()); assertEquals("GET", data.template().method()); assertEquals(MediaType.APPLICATION_JSON_VALUE, data.template().headers().get("Accept").iterator().next()); - assertEquals("id", data.indexToName().get(0).iterator().next()); + assertEquals("anotherId", data.indexToName().get(0).iterator().next()); + assertEquals("id", data.indexToName().get(1).iterator().next()); } @Test public void testProcessAnnotations_SimplePost() throws Exception { Method method = TestTemplate_Simple.class.getDeclaredMethod("postTest", - TestObject.class); + String.class, TestObject.class); MethodMetadata data = this.contract .parseAndValidateMetadata(method.getDeclaringClass(), method); - assertEquals("", data.template().url()); + assertEquals("/prepend/{anotherId}", data.template().url()); assertEquals("POST", data.template().method()); assertEquals(MediaType.APPLICATION_JSON_VALUE, data.template().headers().get("Accept").iterator().next()); + assertEquals("anotherId", data.indexToName().get(0).iterator().next()); } @@ -188,14 +200,16 @@ public class SpringMvcContractTests { @Test public void testProcessAnnotations_Advanced3() throws Exception { - Method method = TestTemplate_Simple.class.getDeclaredMethod("getTest"); + Method method = TestTemplate_Simple.class.getDeclaredMethod("getTest", + String.class); MethodMetadata data = this.contract .parseAndValidateMetadata(method.getDeclaringClass(), method); - assertEquals("", data.template().url()); + assertEquals("/prepend/{anotherId}", data.template().url()); assertEquals("GET", data.template().method()); assertEquals(MediaType.APPLICATION_JSON_VALUE, data.template().headers().get("Accept").iterator().next()); + assertEquals("anotherId", data.indexToName().get(0).iterator().next()); } @Test @@ -262,15 +276,20 @@ public class SpringMvcContractTests { return false; } + @RequestMapping("/prepend/{anotherId}") public interface TestTemplate_Simple { @RequestMapping(value = "/test/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) - ResponseEntity getTest(@PathVariable("id") String id); + ResponseEntity getTest(@PathVariable String anotherId, @PathVariable String id); @RequestMapping(method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) - TestObject getTest(); + TestObject getTest(@PathVariable String anotherId); @RequestMapping(method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE) - TestObject postTest(@RequestBody TestObject object); + TestObject postTest(@PathVariable String anotherId, @RequestBody TestObject object); + } + + public interface TestTemplate_Simple_Extending extends TestTemplate_Simple{ + } public interface TestTemplate_Headers {