Add support for placeholders to Feign spring-mvc RequestMapping annotation.
Fixes gh-894
This commit is contained in:
committed by
Dave Syer
parent
8b306df132
commit
2b40952429
@@ -31,12 +31,17 @@ import org.springframework.cloud.netflix.feign.AnnotatedParameterProcessor;
|
||||
import org.springframework.cloud.netflix.feign.annotation.PathVariableParameterProcessor;
|
||||
import org.springframework.cloud.netflix.feign.annotation.RequestHeaderParameterProcessor;
|
||||
import org.springframework.cloud.netflix.feign.annotation.RequestParamParameterProcessor;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
import org.springframework.core.DefaultParameterNameDiscoverer;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
import feign.Contract;
|
||||
@@ -51,7 +56,7 @@ import static org.springframework.core.annotation.AnnotatedElementUtils.findMerg
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
public class SpringMvcContract extends Contract.BaseContract {
|
||||
public class SpringMvcContract extends Contract.BaseContract implements ResourceLoaderAware {
|
||||
|
||||
private static final String ACCEPT = "Accept";
|
||||
|
||||
@@ -64,6 +69,7 @@ public class SpringMvcContract extends Contract.BaseContract {
|
||||
|
||||
private final ConversionService conversionService;
|
||||
private final Param.Expander expander;
|
||||
private ResourceLoader resourceLoader = new DefaultResourceLoader();
|
||||
|
||||
public SpringMvcContract() {
|
||||
this(Collections.<AnnotatedParameterProcessor> emptyList());
|
||||
@@ -94,6 +100,11 @@ public class SpringMvcContract extends Contract.BaseContract {
|
||||
this.expander = new ConvertingExpander(conversionService);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResourceLoader(ResourceLoader resourceLoader) {
|
||||
this.resourceLoader = resourceLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodMetadata parseAndValidateMetadata(Class<?> targetType, Method method) {
|
||||
this.processedMethods.put(Feign.configKey(targetType, method), method);
|
||||
@@ -108,6 +119,7 @@ public class SpringMvcContract extends Contract.BaseContract {
|
||||
checkState(pathValue != null,
|
||||
"RequestMapping.value() was empty on type %s",
|
||||
method.getDeclaringClass().getName());
|
||||
pathValue = resolve(pathValue);
|
||||
if (!pathValue.startsWith("/")) {
|
||||
pathValue = "/" + pathValue;
|
||||
}
|
||||
@@ -148,6 +160,7 @@ public class SpringMvcContract extends Contract.BaseContract {
|
||||
if (methodMapping.value().length > 0) {
|
||||
String pathValue = emptyToNull(methodMapping.value()[0]);
|
||||
if (pathValue != null) {
|
||||
pathValue = resolve(pathValue);
|
||||
// Append path from @RequestMapping if value is present on method
|
||||
if (!pathValue.startsWith("/")
|
||||
&& !data.template().toString().endsWith("/")) {
|
||||
@@ -169,6 +182,15 @@ public class SpringMvcContract extends Contract.BaseContract {
|
||||
data.indexToExpander(new LinkedHashMap<Integer, Param.Expander>());
|
||||
}
|
||||
|
||||
private String resolve(String value) {
|
||||
if (StringUtils.hasText(value)
|
||||
&& this.resourceLoader instanceof ConfigurableApplicationContext) {
|
||||
return ((ConfigurableApplicationContext) this.resourceLoader).getEnvironment()
|
||||
.resolvePlaceholders(value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private void checkAtMostOne(Method method, Object[] values, String fieldName) {
|
||||
checkState(values != null && (values.length == 0 || values.length == 1),
|
||||
"Method %s can only contain at most 1 %s field. Found: %s",
|
||||
@@ -312,7 +334,7 @@ public class SpringMvcContract extends Contract.BaseContract {
|
||||
|
||||
@Override
|
||||
public Collection<String> setTemplateParameter(String name,
|
||||
Collection<String> rest) {
|
||||
Collection<String> rest) {
|
||||
return addTemplatedParam(rest, name);
|
||||
}
|
||||
}
|
||||
@@ -331,4 +353,4 @@ public class SpringMvcContract extends Contract.BaseContract {
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -142,6 +142,9 @@ public class FeignClientTests {
|
||||
@RequestMapping(method = RequestMethod.GET, value = "/hello")
|
||||
Hello getHello();
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET, value = "${feignClient.methodLevelRequestMappingPath}")
|
||||
Hello getHelloUsingPropertyPlaceHolder();
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET, value = "/hello")
|
||||
Single<Hello> getHelloSingle();
|
||||
|
||||
@@ -309,6 +312,11 @@ public class FeignClientTests {
|
||||
return new Hello(HELLO_WORLD_1);
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET, value = "/hello2")
|
||||
public Hello getHello2() {
|
||||
return new Hello(OI_TERRA_2);
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET, value = "/hellos")
|
||||
public List<Hello> getHellos() {
|
||||
ArrayList<Hello> hellos = getHelloList();
|
||||
@@ -398,6 +406,13 @@ public class FeignClientTests {
|
||||
assertNotNull("invocationHandler was null", invocationHandler);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequestMappingClassLevelPropertyReplacement() {
|
||||
Hello hello = this.testClient.getHelloUsingPropertyPlaceHolder();
|
||||
assertNotNull("hello was null", hello);
|
||||
assertEquals("first hello didn't match", new Hello(OI_TERRA_2), hello);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleType() {
|
||||
Hello hello = this.testClient.getHello();
|
||||
|
||||
@@ -42,4 +42,5 @@ zuul:
|
||||
url: http://localhost:8081
|
||||
path: /stores/**
|
||||
feignClient:
|
||||
localappName: localapp
|
||||
localappName: localapp
|
||||
methodLevelRequestMappingPath: /hello2
|
||||
Reference in New Issue
Block a user