From d356e571340c26768e706633d082c20d9a554b64 Mon Sep 17 00:00:00 2001 From: lowzj Date: Wed, 15 Jun 2016 10:46:29 +0800 Subject: [PATCH] update RequestParamParameterProcessor to support map param fixes gh-1097 --- .../RequestParamParameterProcessor.java | 19 ++++++++++------- .../feign/support/SpringMvcContract.java | 14 ++++++++++++- .../feign/support/SpringMvcContractTests.java | 21 ++++++++++++++++++- 3 files changed, 44 insertions(+), 10 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 a67da38b..950f91cc 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 @@ -47,15 +47,18 @@ public class RequestParamParameterProcessor implements AnnotatedParameterProcess 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); + if (emptyToNull(name) != null) { + context.setParameterName(name); - MethodMetadata data = context.getMethodMetadata(); - Collection query = context.setTemplateParameter(name, - data.template().queries().get(name)); - data.template().query(name, query); + MethodMetadata data = context.getMethodMetadata(); + Collection query = context.setTemplateParameter(name, + data.template().queries().get(name)); + data.template().query(name, query); + } else { + // supports `Map` types + MethodMetadata data = context.getMethodMetadata(); + data.queryMapIndex(context.getParameterIndex()); + } 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 34b1a643..0afec31a 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 @@ -18,6 +18,7 @@ package org.springframework.cloud.netflix.feign.support; import java.lang.annotation.Annotation; import java.lang.reflect.Method; +import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -27,6 +28,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import org.springframework.beans.BeanUtils; import org.springframework.cloud.netflix.feign.AnnotatedParameterProcessor; import org.springframework.cloud.netflix.feign.annotation.PathVariableParameterProcessor; import org.springframework.cloud.netflix.feign.annotation.RequestHeaderParameterProcessor; @@ -313,8 +315,9 @@ public class SpringMvcContract extends Contract.BaseContract Object defaultValue = AnnotationUtils.getDefaultValue(parameterAnnotation); if (defaultValue instanceof String && defaultValue.equals(annotationAttributes.get(AnnotationUtils.VALUE))) { + Type[] parameterTypes = method.getGenericParameterTypes(); String[] parameterNames = PARAMETER_NAME_DISCOVERER.getParameterNames(method); - if (parameterNames != null && parameterNames.length > parameterIndex) { + if (shouldAddParameterName(parameterIndex, parameterTypes, parameterNames)) { annotationAttributes.put(AnnotationUtils.VALUE, parameterNames[parameterIndex]); } @@ -323,6 +326,15 @@ public class SpringMvcContract extends Contract.BaseContract parameterAnnotation.annotationType(), null); } + private boolean shouldAddParameterName(int parameterIndex, Type[] parameterTypes, String[] parameterNames) { + // has a parameter name + return parameterNames != null && parameterNames.length > parameterIndex + // has a type + && parameterTypes != null && parameterTypes.length > parameterIndex + // and it is a simple property + && BeanUtils.isSimpleProperty(parameterTypes[parameterIndex].getClass()); + } + private class SimpleAnnotatedParameterContext implements AnnotatedParameterProcessor.AnnotatedParameterContext { 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 a6616361..139f38ce 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 @@ -19,6 +19,7 @@ package org.springframework.cloud.netflix.feign.support; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.List; +import java.util.Map; import org.junit.Before; import org.junit.Test; @@ -262,6 +263,19 @@ public class SpringMvcContractTests { assertNull(data.indexToExpander().get(0)); } + @Test + public void testProcessAnnotations_MapParams() throws Exception { + Method method = TestTemplate_MapParams.class.getDeclaredMethod("getTest", + Map.class); + MethodMetadata data = this.contract + .parseAndValidateMetadata(method.getDeclaringClass(), method); + + assertEquals("/test", data.template().url()); + assertEquals("GET", data.template().method()); + assertNotNull(data.queryMapIndex()); + assertEquals(0, data.queryMapIndex().intValue()); + } + @Test public void testProcessHeaders() throws Exception { Method method = TestTemplate_Headers.class.getDeclaredMethod("getTest", @@ -279,7 +293,7 @@ public class SpringMvcContractTests { Method method = TestTemplate_Advanced.class.getDeclaredMethod("getTestFallback", String.class, String.class, Integer.class); - assumeTrue(hasJava8ParameterNames(method)); + assumeTrue("does not have java 8 parameter names", hasJava8ParameterNames(method)); MethodMetadata data = this.contract .parseAndValidateMetadata(method.getDeclaringClass(), method); @@ -361,6 +375,11 @@ public class SpringMvcContractTests { ResponseEntity getTest(@RequestParam("id") List id); } + public interface TestTemplate_MapParams { + @RequestMapping(value = "/test", method = RequestMethod.GET) + ResponseEntity getTest(@RequestParam Map params); + } + @JsonAutoDetect @RequestMapping("/advanced") public interface TestTemplate_Advanced {