Compare commits

...
Author SHA1 Message Date
buildmaster 61afb5dcd6 Update SNAPSHOT to 2.1.0.RC1 2018-12-11 16:37:40 +00:00
Ryan Baxter 20017afdca Merge remote-tracking branch 'origin/2.0.x' 2018-12-11 10:04:16 -05:00
Ryan Baxter f267c2255b Merge remote-tracking branch 'origin/2.0.x' 2018-12-11 09:12:30 -05:00
Ryan Baxter dd7b869a12 Uncommenting assert 2018-12-10 12:30:03 -05:00
Momo d46fb3a92e Add support for feign's QueryMap annotation for Object mapping (#79)
* Add QueryMapParameterProcessor

* Add license to QueryMapParameterProcessor

* Use SpringQueryMap instead of QueryMap. Add test.

* Add documentation and license to SpringQueryMap

* SpringQueryMap docs

* Fix typos
2018-12-06 21:26:36 +01:00
buildmaster cc2fe823c3 Going back to snapshots 2018-11-18 09:42:08 +00:00
buildmaster f1975e5200 Update SNAPSHOT to 2.1.0.M2 2018-11-18 09:41:37 +00:00
Ryan Baxter e85e74e311 Merge remote-tracking branch 'origin/2.0.x' 2018-10-02 13:08:37 -04:00
buildmaster 71675455a3 Going back to snapshots 2018-09-21 21:40:58 +00:00
buildmaster a39e6316b5 Update SNAPSHOT to Greenwich.M1 2018-09-21 21:40:12 +00:00
Kerwin Bryant 3e3e486648 Support to set loadBalancerKey (#50)
* Support to override CachingSpringLoadBalancerFactory to customize the FeignLoadBalancer instance.
2018-09-12 14:38:15 -04:00
Spencer Gibb 15bda96e91 Merge branch '2.0.x' 2018-09-05 16:09:38 -04:00
Halvdan Hoem Grelland 52bea35160 Support Spring formatting annotations for params (#48)
* Add factory for Param.Expander using ConversionService. Instances use ConversionService and passes annotations (through TypeDescriptor) - ConversionService can now pick up @DateTimeFormat and @NumberFormat and convert the params applying those.
2018-08-15 07:19:24 -04:00
Spencer Gibb 7148cce790 Upgrades to openfeign 9.7.0
fixes gh-53
2018-08-06 11:52:45 -04:00
Spencer Gibb 88fae41f02 Updates to work with boot 2.1.0 2018-08-03 15:04:17 -04:00
35 changed files with 562 additions and 65 deletions
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-openfeign</artifactId>
<version>2.0.3.BUILD-SNAPSHOT</version>
<version>2.1.0.RC1</version>
</parent>
<artifactId>spring-cloud-openfeign-docs</artifactId>
<packaging>pom</packaging>
@@ -425,4 +425,37 @@ public class FooConfiguration {
return Logger.Level.FULL;
}
}
=== Feign `@QueryMap` support
The OpenFeign `@QueryMap` annotation provides support for POJOs to be used as
GET parameter maps. Unfortunately, the default OpenFeign QueryMap annotation is
incompatible with Spring because it lacks a `value` property.
Spring Cloud OpenFeign provides an equivalent `@SpringQueryMap` annotation, which
is used to annotate a POJO or Map parameter as a query parameter map.
For example, the `Params` class defines parameters `param1` and `param2`:
[source,java,indent=0]
----
// Params.java
public class Params {
private String param1;
private String param2;
// [Getters and setters omitted for brevity]
}
----
The following feign client uses the `Params` class by using the `@SpringQueryMap` annotation:
[source,java,indent=0]
----
@FeignClient("demo")
public class DemoTemplate {
@GetMapping(path = "/demo")
String demoEndpoint(@SpringQueryMap Params params);
}
----
+4 -4
View File
@@ -3,14 +3,14 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-cloud-openfeign</artifactId>
<version>2.0.3.BUILD-SNAPSHOT</version>
<version>2.1.0.RC1</version>
<packaging>pom</packaging>
<name>Spring Cloud OpenFeign</name>
<description>Spring Cloud OpenFeign</description>
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-build</artifactId>
<version>2.0.4.RELEASE</version>
<version>2.1.0.RC2</version>
<relativePath />
</parent>
<scm>
@@ -22,8 +22,8 @@
<properties>
<main.basedir>${basedir}</main.basedir>
<jackson.version>2.7.3</jackson.version>
<spring-cloud-commons.version>2.0.2.BUILD-SNAPSHOT</spring-cloud-commons.version>
<spring-cloud-netflix.version>2.0.2.BUILD-SNAPSHOT</spring-cloud-netflix.version>
<spring-cloud-commons.version>2.1.0.RC1</spring-cloud-commons.version>
<spring-cloud-netflix.version>2.1.0.RC1</spring-cloud-netflix.version>
<!-- Plugin versions -->
<maven-compiler-plugin.version>3.6.1</maven-compiler-plugin.version>
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-openfeign</artifactId>
<version>2.0.3.BUILD-SNAPSHOT</version>
<version>2.1.0.RC1</version>
<relativePath>..</relativePath> <!-- lookup parent from repository -->
</parent>
<artifactId>spring-cloud-openfeign-core</artifactId>
@@ -0,0 +1,53 @@
/*
* Copyright 2013-2018 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.openfeign;
import feign.QueryMap;
import org.springframework.core.annotation.AliasFor;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Spring MVC equivalent of OpenFeign's {@link feign.QueryMap} parameter annotation.
*
* @author Aram Peres
* @see feign.QueryMap
* @see org.springframework.cloud.openfeign.annotation.QueryMapParameterProcessor
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
public @interface SpringQueryMap {
/**
* Alias for {@link #encoded()}.
*
* @see QueryMap#encoded()
*/
@AliasFor("encoded")
boolean value() default false;
/**
* Specifies whether parameter names and values are already encoded.
*
* @see QueryMap#encoded()
*/
@AliasFor("value")
boolean encoded() default false;
}
@@ -0,0 +1,51 @@
/*
* Copyright 2013-2018 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.cloud.openfeign.annotation;
import feign.MethodMetadata;
import org.springframework.cloud.openfeign.AnnotatedParameterProcessor;
import org.springframework.cloud.openfeign.SpringQueryMap;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
/**
* {@link SpringQueryMap} parameter processor.
*
* @author Aram Peres
* @see AnnotatedParameterProcessor
*/
public class QueryMapParameterProcessor implements AnnotatedParameterProcessor {
private static final Class<SpringQueryMap> ANNOTATION = SpringQueryMap.class;
@Override
public Class<? extends Annotation> getAnnotationType() {
return ANNOTATION;
}
@Override
public boolean processArgument(AnnotatedParameterContext context, Annotation annotation, Method method) {
int paramIndex = context.getParameterIndex();
MethodMetadata metadata = context.getMethodMetadata();
if (metadata.queryMapIndex() == null) {
metadata.queryMapIndex(paramIndex);
metadata.queryMapEncoded(SpringQueryMap.class.cast(annotation).encoded());
}
return true;
}
}
@@ -36,8 +36,8 @@ import com.netflix.loadbalancer.ILoadBalancer;
*/
public class CachingSpringLoadBalancerFactory {
private final SpringClientFactory factory;
private LoadBalancedRetryFactory loadBalancedRetryFactory = null;
protected final SpringClientFactory factory;
protected LoadBalancedRetryFactory loadBalancedRetryFactory = null;
private volatile Map<String, FeignLoadBalancer> cache = new ConcurrentReferenceHashMap<>();
@@ -118,7 +118,7 @@ public class FeignLoadBalancer extends
private final Request request;
private final Client client;
RibbonRequest(Client client, Request request, URI uri) {
protected RibbonRequest(Client client, Request request, URI uri) {
this.client = client;
setUri(uri);
this.request = toRequest(request);
@@ -170,6 +170,13 @@ public class FeignLoadBalancer extends
};
}
public Request getRequest() {
return request;
}
public Client getClient() {
return client;
}
@Override
public Object clone() {
@@ -182,7 +189,7 @@ public class FeignLoadBalancer extends
private final URI uri;
private final Response response;
RibbonResponse(URI uri, Response response) {
protected RibbonResponse(URI uri, Response response) {
this.uri = uri;
this.response = response;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2013-2016 the original author or authors.
* Copyright 2013-2018 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.
@@ -18,6 +18,7 @@ package org.springframework.cloud.openfeign.support;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
@@ -30,14 +31,17 @@ import java.util.Map;
import org.springframework.cloud.openfeign.AnnotatedParameterProcessor;
import org.springframework.cloud.openfeign.annotation.PathVariableParameterProcessor;
import org.springframework.cloud.openfeign.annotation.QueryMapParameterProcessor;
import org.springframework.cloud.openfeign.annotation.RequestHeaderParameterProcessor;
import org.springframework.cloud.openfeign.annotation.RequestParamParameterProcessor;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.MethodParameter;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.core.convert.ConversionService;
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;
@@ -58,6 +62,8 @@ import feign.Param;
/**
* @author Spencer Gibb
* @author Abhijit Sarkar
* @author Halvdan Hoem Grelland
* @author Aram Peres
*/
public class SpringMvcContract extends Contract.BaseContract
implements ResourceLoaderAware {
@@ -66,13 +72,18 @@ public class SpringMvcContract extends Contract.BaseContract
private static final String CONTENT_TYPE = "Content-Type";
private static final TypeDescriptor STRING_TYPE_DESCRIPTOR =
TypeDescriptor.valueOf(String.class);
private static final TypeDescriptor ITERABLE_TYPE_DESCRIPTOR =
TypeDescriptor.valueOf(Iterable.class);
private static final ParameterNameDiscoverer PARAMETER_NAME_DISCOVERER = new DefaultParameterNameDiscoverer();
private final Map<Class<? extends Annotation>, AnnotatedParameterProcessor> annotatedArgumentProcessors;
private final Map<String, Method> processedMethods = new HashMap<>();
private final ConversionService conversionService;
private final Param.Expander expander;
private final ConvertingExpanderFactory convertingExpanderFactory;
private ResourceLoader resourceLoader = new DefaultResourceLoader();
public SpringMvcContract() {
@@ -100,7 +111,7 @@ public class SpringMvcContract extends Contract.BaseContract
}
this.annotatedArgumentProcessors = toAnnotatedArgumentProcessorMap(processors);
this.conversionService = conversionService;
this.expander = new ConvertingExpander(conversionService);
this.convertingExpanderFactory = new ConvertingExpanderFactory(conversionService);
}
@Override
@@ -239,14 +250,40 @@ public class SpringMvcContract extends Contract.BaseContract
processParameterAnnotation, method);
}
}
if (isHttpAnnotation && data.indexToExpander().get(paramIndex) == null
&& this.conversionService.canConvert(
method.getParameterTypes()[paramIndex], String.class)) {
data.indexToExpander().put(paramIndex, this.expander);
if (isHttpAnnotation && data.indexToExpander().get(paramIndex) == null) {
TypeDescriptor typeDescriptor = createTypeDescriptor(method, paramIndex);
if (conversionService.canConvert(typeDescriptor, STRING_TYPE_DESCRIPTOR)) {
Param.Expander expander =
convertingExpanderFactory.getExpander(typeDescriptor);
if (expander != null) {
data.indexToExpander().put(paramIndex, expander);
}
}
}
return isHttpAnnotation;
}
private static TypeDescriptor createTypeDescriptor(Method method, int paramIndex) {
Parameter parameter = method.getParameters()[paramIndex];
MethodParameter methodParameter = MethodParameter.forParameter(parameter);
TypeDescriptor typeDescriptor = new TypeDescriptor(methodParameter);
// Feign applies the Param.Expander to each element of an Iterable, so in those
// cases we need to provide a TypeDescriptor of the element.
if (typeDescriptor.isAssignableTo(ITERABLE_TYPE_DESCRIPTOR)) {
TypeDescriptor elementTypeDescriptor =
typeDescriptor.getElementTypeDescriptor();
checkState(elementTypeDescriptor != null,
"Could not resolve element type of Iterable type %s. Not declared?",
typeDescriptor);
typeDescriptor = elementTypeDescriptor;
}
return typeDescriptor;
}
private void parseProduces(MethodMetadata md, Method method,
RequestMapping annotation) {
String[] serverProduces = annotation.produces();
@@ -297,6 +334,7 @@ public class SpringMvcContract extends Contract.BaseContract
annotatedArgumentResolvers.add(new PathVariableParameterProcessor());
annotatedArgumentResolvers.add(new RequestParamParameterProcessor());
annotatedArgumentResolvers.add(new RequestHeaderParameterProcessor());
annotatedArgumentResolvers.add(new QueryMapParameterProcessor());
return annotatedArgumentResolvers;
}
@@ -361,6 +399,10 @@ public class SpringMvcContract extends Contract.BaseContract
}
}
/**
* @deprecated Not used internally anymore. Will be removed in the future.
*/
@Deprecated
public static class ConvertingExpander implements Param.Expander {
private final ConversionService conversionService;
@@ -375,4 +417,21 @@ public class SpringMvcContract extends Contract.BaseContract
}
}
private static class ConvertingExpanderFactory {
private final ConversionService conversionService;
ConvertingExpanderFactory(ConversionService conversionService) {
this.conversionService = conversionService;
}
Param.Expander getExpander(TypeDescriptor typeDescriptor) {
return value -> {
Object converted = this.conversionService.convert(
value, typeDescriptor, STRING_TYPE_DESCRIPTOR);
return (String) converted;
};
}
}
}
@@ -30,8 +30,10 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.cloud.openfeign.test.NoSecurityConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.test.annotation.DirtiesContext;
@@ -144,6 +146,7 @@ public class FeignClientUsingPropertiesTests {
@Configuration
@EnableAutoConfiguration
@RestController
@Import(NoSecurityConfiguration.class)
protected static class Application {
@RequestMapping(method = RequestMethod.GET, value = "/foo")
@@ -28,6 +28,7 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.commons.httpclient.HttpClientConfiguration;
import org.springframework.cloud.test.ClassPathExclusions;
@@ -49,8 +50,11 @@ public class FeignHttpClientConfigurationTests {
@Before
public void setUp() {
context = new SpringApplicationBuilder().properties("debug=true","feign.httpclient.disableSslValidation=true").web(false)
.sources(HttpClientConfiguration.class, FeignAutoConfiguration.class).run();
context = new SpringApplicationBuilder()
.properties("debug=true","feign.httpclient.disableSslValidation=true")
.web(WebApplicationType.NONE)
.sources(HttpClientConfiguration.class, FeignAutoConfiguration.class)
.run();
}
@After
@@ -34,8 +34,10 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.cloud.openfeign.test.NoSecurityConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.util.ReflectionUtils;
@@ -103,6 +105,7 @@ public class FeignHttpClientUrlTests {
@EnableAutoConfiguration
@RestController
@EnableFeignClients(clients = { UrlClient.class, BeanUrlClient.class, BeanUrlClientNoProtocol.class })
@Import(NoSecurityConfiguration.class)
protected static class TestConfig {
@RequestMapping(method = RequestMethod.GET, value = "/hello")
@@ -25,6 +25,7 @@ import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.commons.httpclient.HttpClientConfiguration;
import org.springframework.cloud.commons.httpclient.OkHttpClientFactory;
@@ -45,7 +46,7 @@ public class FeignOkHttpConfigurationTests {
@Before
public void setUp() {
context = new SpringApplicationBuilder().properties("debug=true","feign.httpclient.disableSslValidation=true",
"feign.okhttp.enabled=true", "feign.httpclient.enabled=false").web(false)
"feign.okhttp.enabled=true", "feign.httpclient.enabled=false").web(WebApplicationType.NONE)
.sources(HttpClientConfiguration.class, FeignAutoConfiguration.class).run();
}
@@ -28,7 +28,9 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.cloud.openfeign.test.NoSecurityConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.annotation.DirtiesContext;
@@ -201,6 +203,7 @@ public class SpringDecoderTests extends FeignClientFactoryBean {
@Configuration
@EnableAutoConfiguration
@RestController
@Import(NoSecurityConfiguration.class)
protected static class Application implements TestClient {
@Override
@@ -22,6 +22,7 @@ import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.cloud.client.loadbalancer.LoadBalancerAutoConfiguration;
import org.springframework.cloud.openfeign.ribbon.CachingSpringLoadBalancerFactory;
@@ -51,7 +52,7 @@ public class SpringRetryDisabledTests {
@Before
public void setUp() {
context = new SpringApplicationBuilder().web(false)
context = new SpringApplicationBuilder().web(WebApplicationType.NONE)
.sources(RibbonAutoConfiguration.class, LoadBalancerAutoConfiguration.class, RibbonClientConfiguration.class,
FeignRibbonClientAutoConfiguration.class).run();
}
@@ -35,8 +35,10 @@ import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.encoding.app.client.InvoiceClient;
import org.springframework.cloud.openfeign.encoding.app.domain.Invoice;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.cloud.openfeign.test.NoSecurityConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.annotation.DirtiesContext;
@@ -76,6 +78,7 @@ public class FeignAcceptEncodingTests {
@EnableFeignClients(clients = InvoiceClient.class)
@RibbonClient(name = "local", configuration = LocalRibbonClientConfiguration.class)
@SpringBootApplication(scanBasePackages = "org.springframework.cloud.openfeign.encoding.app")
@Import(NoSecurityConfiguration.class)
public static class Application {
}
@@ -33,8 +33,10 @@ import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.encoding.app.client.InvoiceClient;
import org.springframework.cloud.openfeign.encoding.app.domain.Invoice;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.cloud.openfeign.test.NoSecurityConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@@ -79,6 +81,7 @@ public class FeignContentEncodingTests {
@EnableFeignClients(clients = InvoiceClient.class)
@RibbonClient(name = "local", configuration = LocalRibbonClientConfiguration.class)
@SpringBootApplication(scanBasePackages = "org.springframework.cloud.openfeign.encoding.app")
@Import(NoSecurityConfiguration.class)
public static class Application {
}
@@ -16,17 +16,45 @@
package org.springframework.cloud.openfeign.hystrix.security;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.hystrix.security.app.CustomConcurrenyStrategy;
import org.springframework.cloud.openfeign.hystrix.security.app.ProxyUsernameController;
import org.springframework.cloud.openfeign.hystrix.security.app.TestInterceptor;
import org.springframework.cloud.openfeign.hystrix.security.app.UsernameClient;
import org.springframework.cloud.openfeign.hystrix.security.app.UsernameController;
import org.springframework.cloud.openfeign.test.NoSecurityConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
* @author Daniel Lavoie
*/
@Configuration
@SpringBootApplication
@EnableAutoConfiguration
@EnableFeignClients(clients = UsernameClient.class)
@Import(NoSecurityConfiguration.class)
public class HystrixSecurityApplication {
@Bean
public CustomConcurrenyStrategy customConcurrenyStrategy() {
return new CustomConcurrenyStrategy();
}
@Bean
public TestInterceptor testInterceptor() {
return new TestInterceptor();
}
@Bean
public ProxyUsernameController proxyUsernameController() {
return new ProxyUsernameController();
}
@Bean
public UsernameController usernameController() {
return new UsernameController();
}
}
@@ -16,25 +16,36 @@
package org.springframework.cloud.openfeign.hystrix.security;
import java.util.Base64;
import org.junit.Assert;
import com.netflix.hystrix.strategy.HystrixPlugins;
import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;
import com.netflix.loadbalancer.Server;
import com.netflix.loadbalancer.ServerList;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringBootConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.cloud.netflix.hystrix.security.SecurityContextConcurrencyStrategy;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.cloud.netflix.ribbon.StaticServerList;
import org.springframework.cloud.openfeign.hystrix.security.app.CustomConcurrenyStrategy;
import org.springframework.cloud.openfeign.valid.FeignClientTests;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.client.RestTemplate;
import com.netflix.hystrix.strategy.HystrixPlugins;
import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;
import java.util.Base64;
import static org.assertj.core.api.Assertions.assertThat;
@@ -45,9 +56,8 @@ import static org.assertj.core.api.Assertions.assertThat;
*/
@RunWith(SpringRunner.class)
@DirtiesContext
@SpringBootTest(classes = HystrixSecurityApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT,
properties = { "username.ribbon.listOfServers=localhost:${local.server.port}",
"feign.hystrix.enabled=true"})
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT,
properties = { "feign.hystrix.enabled=true"})
@ActiveProfiles("proxysecurity")
public class HystrixSecurityTests {
@Autowired
@@ -56,7 +66,7 @@ public class HystrixSecurityTests {
@LocalServerPort
private String serverPort;
//TODOO: move to constants in TestAutoConfiguration
//TODO: move to constants in TestAutoConfiguration
private String username = "user";
private String password = "password";
@@ -69,19 +79,21 @@ public class HystrixSecurityTests {
@Test
public void testFeignHystrixSecurity() {
HttpHeaders headers = HystrixSecurityTests.createBasicAuthHeader(username,
password);
HttpHeaders headers = createBasicAuthHeader(username, password);
String usernameResult = new RestTemplate()
ResponseEntity<String> entity = new RestTemplate()
.exchange("http://localhost:" + serverPort + "/proxy-username",
HttpMethod.GET, new HttpEntity<Void>(headers), String.class)
.getBody();
HttpMethod.GET, new HttpEntity<Void>(headers), String.class);
Assert.assertTrue("Username should have been intercepted by feign interceptor.",
username.equals(usernameResult));
assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK);
Assert.assertTrue("Custom hook should have been called.",
customConcurrenyStrategy.isHookCalled());
assertThat(entity.getBody())
.as("Username should have been intercepted by feign interceptor.")
.isEqualTo(username);
assertThat(customConcurrenyStrategy.isHookCalled())
.as("Custom hook should have been called.")
.isTrue();
}
public static HttpHeaders createBasicAuthHeader(final String username,
@@ -97,4 +109,21 @@ public class HystrixSecurityTests {
}
};
}
@SpringBootConfiguration
@Import(HystrixSecurityApplication.class)
@RibbonClient(name = "username", configuration = LocalRibbonClientConfiguration.class)
protected static class TestConfig { }
protected static class LocalRibbonClientConfiguration {
@LocalServerPort
private int port = 0;
@Bean
public ServerList<Server> ribbonServerList() {
return new StaticServerList<>(new Server("localhost", this.port));
}
}
}
@@ -1,10 +1,9 @@
package org.springframework.cloud.openfeign.hystrix.security.app;
import java.util.concurrent.Callable;
import org.springframework.stereotype.Component;
import com.netflix.hystrix.strategy.concurrency.HystrixConcurrencyStrategy;
@Component
import java.util.concurrent.Callable;
public class CustomConcurrenyStrategy extends HystrixConcurrencyStrategy {
private boolean hookCalled;
@@ -28,7 +28,6 @@ import org.springframework.stereotype.Component;
*
* @author Daniel Lavoie
*/
@Component
public class TestInterceptor implements RequestInterceptor {
@Override
@@ -26,5 +26,5 @@ import org.springframework.web.bind.annotation.RequestMapping;
public interface UsernameClient {
@RequestMapping("/username")
public String getUsername();
String getUsername();
}
@@ -23,6 +23,9 @@ import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import com.netflix.loadbalancer.BaseLoadBalancer;
import com.netflix.loadbalancer.RoundRobinRule;
import com.netflix.loadbalancer.reactive.LoadBalancerCommand;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
@@ -168,4 +171,34 @@ public class FeignLoadBalancerTests {
}
@Test
public void testOverrideFeignLoadBalancer() throws Exception {
when(this.config.get(IsSecure)).thenReturn(false);
Server server1 = new Server("foo", 6666);
Server server2 = new Server("foo", 7777);
BaseLoadBalancer baseLoadBalancer = new BaseLoadBalancer();
baseLoadBalancer.setRule(new RoundRobinRule() {
@Override
public Server choose(Object loadBalancerKey) {
return loadBalancerKey == null ? server2 : server1;
}
});
this.feignLoadBalancer = new FeignLoadBalancer(baseLoadBalancer, this.config,
this.inspector) {
protected void customizeLoadBalancerCommandBuilder(final FeignLoadBalancer.RibbonRequest request, final IClientConfig config,
final LoadBalancerCommand.Builder<FeignLoadBalancer.RibbonResponse> builder) {
builder.withServerLocator(request.getRequest().headers().get("c_ip"));
}
};
Request request = new RequestTemplate().method("GET").request();
RibbonResponse resp = this.feignLoadBalancer.executeWithLoadBalancer(new RibbonRequest(this.delegate, request,
new URI(request.url())), null);
assertThat(resp.getRequestedURI().getPort(), is(7777));
request = new RequestTemplate().method("GET").header("c_ip", "666").request();
resp = this.feignLoadBalancer.executeWithLoadBalancer(new RibbonRequest(this.delegate, request,
new URI(request.url())), null);
assertThat(resp.getRequestedURI().getPort(), is(6666));
}
}
@@ -26,12 +26,15 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.cloud.netflix.ribbon.RibbonClients;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.cloud.netflix.ribbon.StaticServerList;
import org.springframework.cloud.openfeign.test.NoSecurityConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -84,16 +87,16 @@ public class FeignRibbonClientPathTests {
@FeignClient(name = "localapp", path = "/base/path")
protected interface TestClient1 extends TestClient { }
@FeignClient(name = "localapp", path = "base/path")
@FeignClient(name = "localapp1", path = "base/path")
protected interface TestClient2 extends TestClient { }
@FeignClient(name = "localapp", path = "base/path/")
@FeignClient(name = "localapp2", path = "base/path/")
protected interface TestClient3 extends TestClient { }
@FeignClient(name = "localapp", path = "/base/path/")
@FeignClient(name = "localapp3", path = "/base/path/")
protected interface TestClient4 extends TestClient { }
@FeignClient(name = "localapp", path = "${test.path.prefix}")
@FeignClient(name = "localapp4", path = "${test.path.prefix}")
protected interface TestClient5 extends TestClient { }
@Configuration
@@ -104,7 +107,8 @@ public class FeignRibbonClientPathTests {
TestClient1.class, TestClient2.class, TestClient3.class, TestClient4.class,
TestClient5.class
})
@RibbonClient(name = "localapp", configuration = LocalRibbonClientConfiguration.class)
@RibbonClients(defaultConfiguration = LocalRibbonClientConfiguration.class)
@Import(NoSecurityConfiguration.class)
public static class Application {
@RequestMapping(method = RequestMethod.GET, value = "/hello")
@@ -31,8 +31,10 @@ import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.cloud.netflix.ribbon.StaticServerList;
import org.springframework.cloud.openfeign.test.NoSecurityConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -78,6 +80,7 @@ public class FeignRibbonClientRetryTests {
@RestController
@EnableFeignClients(clients = TestClient.class)
@RibbonClient(name = "localapp", configuration = LocalRibbonClientConfiguration.class)
@Import(NoSecurityConfiguration.class)
public static class Application {
private AtomicInteger retries = new AtomicInteger(1);
@@ -23,6 +23,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -32,7 +33,6 @@ import org.springframework.test.context.junit4.SpringRunner;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.springframework.boot.test.util.EnvironmentTestUtils.addEnvironment;
/**
* @author Ryan Baxter
@@ -63,12 +63,12 @@ public class FeignHttpClientPropertiesTests {
@Test
public void testCustomization() {
addEnvironment(this.context, "feign.httpclient.maxConnections=2",
TestPropertyValues.of("feign.httpclient.maxConnections=2",
"feign.httpclient.connectionTimeout=2",
"feign.httpclient.maxConnectionsPerRoute=2",
"feign.httpclient.timeToLive=2",
"feign.httpclient.disableSslValidation=true",
"feign.httpclient.followRedirects=false");
"feign.httpclient.followRedirects=false").applyTo(this.context);
setupContext();
assertEquals(2, getProperties().getMaxConnections());
assertEquals(2, getProperties().getConnectionTimeout());
@@ -1,5 +1,5 @@
/*
* Copyright 2013-2016 the original author or authors.
* Copyright 2013-2018 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.
@@ -18,12 +18,25 @@ package org.springframework.cloud.openfeign.support;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import feign.Param;
import org.junit.Before;
import org.junit.Test;
import org.springframework.cloud.openfeign.SpringQueryMap;
import org.springframework.core.convert.ConversionService;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.format.annotation.NumberFormat;
import org.springframework.format.number.NumberStyleFormatter;
import org.springframework.format.support.FormattingConversionServiceFactoryBean;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.MultiValueMap;
@@ -48,6 +61,8 @@ import feign.MethodMetadata;
/**
* @author chadjaros
* @author Halvdan Hoem Grelland
* @author Aram Peres
*/
public class SpringMvcContractTests {
private static final Class<?> EXECUTABLE_TYPE;
@@ -67,7 +82,12 @@ public class SpringMvcContractTests {
@Before
public void setup() {
this.contract = new SpringMvcContract();
FormattingConversionServiceFactoryBean conversionServiceFactoryBean
= new FormattingConversionServiceFactoryBean();
conversionServiceFactoryBean.afterPropertiesSet();
ConversionService conversionService = conversionServiceFactoryBean.getObject();
this.contract = new SpringMvcContract(Collections.emptyList(), conversionService);
}
@Test
@@ -255,6 +275,47 @@ public class SpringMvcContractTests {
data.template().queries().get("amount").iterator().next());
}
@Test
public void testProcessAnnotations_DateTimeFormatParam() throws Exception {
Method method = TestTemplate_DateTimeFormatParameter.class.getDeclaredMethod(
"getTest", LocalDateTime.class);
MethodMetadata data = this.contract
.parseAndValidateMetadata(method.getDeclaringClass(), method);
Param.Expander expander = data.indexToExpander().get(0);
assertNotNull(expander);
LocalDateTime input = LocalDateTime.of(2001, 10, 12, 23, 56, 3);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(
TestTemplate_DateTimeFormatParameter.CUSTOM_PATTERN);
String expected = formatter.format(input);
assertEquals(expected, expander.expand(input));
}
@Test
public void testProcessAnnotations_NumberFormatParam() throws Exception {
Method method = TestTemplate_NumberFormatParameter.class.getDeclaredMethod(
"getTest", BigDecimal.class);
MethodMetadata data = this.contract
.parseAndValidateMetadata(method.getDeclaringClass(), method);
Param.Expander expander = data.indexToExpander().get(0);
assertNotNull(expander);
NumberStyleFormatter formatter = new NumberStyleFormatter(
TestTemplate_NumberFormatParameter.CUSTOM_PATTERN);
BigDecimal input = BigDecimal.valueOf(1220.345);
String expected = formatter.print(input, Locale.getDefault());
String actual = expander.expand(input);
assertEquals(expected, actual);
}
@Test
public void testProcessAnnotations_Advanced2() throws Exception {
Method method = TestTemplate_Advanced.class.getDeclaredMethod("getTest");
@@ -429,6 +490,20 @@ public class SpringMvcContractTests {
assertEquals("{aParam}", params.get("aParam").iterator().next());
}
@Test
public void testProcessQueryMapObject() throws Exception {
Method method = TestTemplate_QueryMap.class.getDeclaredMethod("queryMapObject",
TestObject.class, String.class);
MethodMetadata data = this.contract
.parseAndValidateMetadata(method.getDeclaringClass(), method);
assertEquals("/queryMapObject", data.template().url());
assertEquals("GET", data.template().method());
assertEquals(0, data.queryMapIndex().intValue());
Map<String, Collection<String>> params = data.template().queries();
assertEquals("{aParam}", params.get("aParam").iterator().next());
}
@Test(expected = IllegalStateException.class)
public void testProcessQueryMapMoreThanOnce() throws Exception {
Method method = TestTemplate_QueryMap.class.getDeclaredMethod(
@@ -514,6 +589,11 @@ public class SpringMvcContractTests {
String queryMapMoreThanOnce(
@RequestParam MultiValueMap<String, String> queryMap1,
@RequestParam MultiValueMap<String, String> queryMap2);
@RequestMapping(path = "/queryMapObject")
String queryMapObject(
@SpringQueryMap TestObject queryMap,
@RequestParam(name = "aParam") String aParam);
}
@JsonAutoDetect
@@ -539,6 +619,24 @@ public class SpringMvcContractTests {
TestObject getTest();
}
public interface TestTemplate_DateTimeFormatParameter {
String CUSTOM_PATTERN = "dd-MM-yyyy HH:mm";
@RequestMapping(method = RequestMethod.GET)
String getTest(@RequestParam(name = "localDateTime")
@DateTimeFormat(pattern = CUSTOM_PATTERN) LocalDateTime localDateTime);
}
public interface TestTemplate_NumberFormatParameter {
String CUSTOM_PATTERN = "$###,###.###";
@RequestMapping(method = RequestMethod.GET)
String getTest(@RequestParam("amount")
@NumberFormat(pattern = CUSTOM_PATTERN) BigDecimal amount);
}
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY, getterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE)
public class TestObject {
@@ -0,0 +1,33 @@
/*
* Copyright 2013-2018 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.springframework.cloud.openfeign.test;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
public class NoSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest().permitAll()
.and()
.csrf().disable();
}
}
@@ -20,6 +20,7 @@ import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.text.ParseException;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -47,10 +48,13 @@ import org.springframework.cloud.openfeign.support.FallbackCommand;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.cloud.netflix.ribbon.RibbonClients;
import org.springframework.cloud.netflix.ribbon.StaticServerList;
import org.springframework.cloud.openfeign.test.NoSecurityConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.format.Formatter;
import org.springframework.format.FormatterRegistry;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
@@ -94,6 +98,7 @@ import rx.Single;
* @author Spencer Gibb
* @author Jakub Narloch
* @author Erik Kringen
* @author Halvdan Hoem Grelland
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = FeignClientTests.Application.class, webEnvironment = WebEnvironment.RANDOM_PORT, value = {
@@ -194,6 +199,11 @@ public class FeignClientTests {
@RequestMapping(method = RequestMethod.GET, path = "/helloparams")
List<String> getParams(@RequestParam("params") List<String> params);
@RequestMapping(method = RequestMethod.GET, path = "/formattedparams")
List<LocalDate> getFormattedParams(
@RequestParam("params")
@DateTimeFormat(pattern = "dd-MM-yyyy") List<LocalDate> params);
@RequestMapping(method = RequestMethod.GET, path = "/hellos")
HystrixCommand<List<Hello>> getHellosHystrix();
@@ -398,6 +408,7 @@ public class FeignClientTests {
@RibbonClient(name = "localapp6", configuration = LocalRibbonClientConfiguration.class),
@RibbonClient(name = "localapp7", configuration = LocalRibbonClientConfiguration.class)
})
@Import(NoSecurityConfiguration.class)
protected static class Application {
// needs to be in parent context to test multiple HystrixClient beans
@@ -491,6 +502,13 @@ public class FeignClientTests {
return params;
}
@RequestMapping(method = RequestMethod.GET, path = "/formattedparams")
public List<LocalDate> getFormattedParams(
@RequestParam("params")
@DateTimeFormat(pattern = "dd-MM-yyyy") List<LocalDate> params) {
return params;
}
@RequestMapping(method = RequestMethod.GET, path = "/noContent")
ResponseEntity<Void> noContent() {
return ResponseEntity.noContent().build();
@@ -633,6 +651,15 @@ public class FeignClientTests {
assertEquals("params size was wrong", list.size(), params.size());
}
@Test
public void testFormattedParams() {
List<LocalDate> list = Arrays.asList(
LocalDate.of(2001, 1, 1), LocalDate.of(2018, 6, 10));
List<LocalDate> params = this.testClient.getFormattedParams(list);
assertNotNull("params was null", params);
assertEquals("params not converted correctly", list, params);
}
@Test
public void testHystrixCommand() throws NoSuchMethodException {
HystrixCommand<List<Hello>> command = this.testClient.getHellosHystrix();
@@ -25,13 +25,16 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.cloud.netflix.ribbon.RibbonClients;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.cloud.netflix.ribbon.StaticServerList;
import org.springframework.cloud.openfeign.test.NoSecurityConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.test.annotation.DirtiesContext;
@@ -95,7 +98,7 @@ public class FeignHttpClientTests {
User getUser(@PathVariable("id") long id);
}
@FeignClient("localapp")
@FeignClient("localapp1")
protected interface UserClient extends UserService {
}
@@ -103,7 +106,11 @@ public class FeignHttpClientTests {
@EnableAutoConfiguration
@RestController
@EnableFeignClients(clients = { TestClient.class, UserClient.class })
@RibbonClient(name = "localapp", configuration = LocalRibbonClientConfiguration.class)
@RibbonClients({
@RibbonClient(name = "localapp", configuration = LocalRibbonClientConfiguration.class),
@RibbonClient(name = "localapp1", configuration = LocalRibbonClientConfiguration.class)
})
@Import(NoSecurityConfiguration.class)
protected static class Application implements UserService {
@RequestMapping(method = RequestMethod.GET, value = "/hello")
@@ -24,13 +24,16 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.cloud.netflix.ribbon.RibbonClients;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.cloud.openfeign.ribbon.LoadBalancerFeignClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.cloud.netflix.ribbon.StaticServerList;
import org.springframework.cloud.openfeign.test.NoSecurityConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.ResponseEntity;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@@ -96,7 +99,7 @@ public class FeignOkHttpTests {
User getUser(@PathVariable("id") long id);
}
@FeignClient("localapp")
@FeignClient("localapp1")
protected interface UserClient extends UserService {
}
@@ -104,7 +107,11 @@ public class FeignOkHttpTests {
@EnableAutoConfiguration
@RestController
@EnableFeignClients(clients = { TestClient.class, UserClient.class })
@RibbonClient(name = "localapp", configuration = LocalRibbonClientConfiguration.class)
@RibbonClients({
@RibbonClient(name = "localapp", configuration = LocalRibbonClientConfiguration.class),
@RibbonClient(name = "localapp1", configuration = LocalRibbonClientConfiguration.class)
})
@Import(NoSecurityConfiguration.class)
protected static class Application implements UserService {
@RequestMapping(method = RequestMethod.GET, value = "/hello")
@@ -24,11 +24,13 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.test.NoSecurityConfiguration;
import org.springframework.cloud.openfeign.testclients.TestClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.cloud.netflix.ribbon.StaticServerList;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -66,6 +68,7 @@ public class FeignClientEnvVarTests {
@RestController
@EnableFeignClients(basePackages = {"${basepackage}"})
@RibbonClient(name = "localapp", configuration = LocalRibbonClientConfiguration.class)
@Import(NoSecurityConfiguration.class)
protected static class Application {
@RequestMapping(method = RequestMethod.GET, value = "/hello")
public String getHello() {
@@ -23,12 +23,15 @@ import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.cloud.netflix.ribbon.RibbonClients;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.cloud.netflix.ribbon.StaticServerList;
import org.springframework.cloud.openfeign.test.NoSecurityConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -65,7 +68,7 @@ public class FeignClientScanningTests {
@SuppressWarnings("unused")
private Client feignClient;
@FeignClient("localapp")
@FeignClient("localapp123")
protected interface TestClient {
@RequestMapping(method = RequestMethod.GET, value = "/hello")
String getHello();
@@ -81,7 +84,8 @@ public class FeignClientScanningTests {
@EnableAutoConfiguration
@RestController
@EnableFeignClients // NO clients attribute. That's what this class is testing!
@RibbonClient(name = "localapp", configuration = LocalRibbonClientConfiguration.class)
@RibbonClients(defaultConfiguration = LocalRibbonClientConfiguration.class)
@Import(NoSecurityConfiguration.class)
protected static class Application {
@RequestMapping(method = RequestMethod.GET, value = "/hello")
public String getHello() {
+2 -3
View File
@@ -5,11 +5,10 @@
<parent>
<artifactId>spring-cloud-dependencies-parent</artifactId>
<groupId>org.springframework.cloud</groupId>
<version>2.0.4.RELEASE</version>
<relativePath/>
<version>2.1.0.RC2</version> <relativePath/>
</parent>
<artifactId>spring-cloud-openfeign-dependencies</artifactId>
<version>2.0.3.BUILD-SNAPSHOT</version>
<version>2.1.0.RC1</version>
<packaging>pom</packaging>
<name>spring-cloud-openfeign-dependencies</name>
<description>Spring Cloud OpenFeign Dependencies</description>
+1 -1
View File
@@ -4,7 +4,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-openfeign</artifactId>
<version>2.0.3.BUILD-SNAPSHOT</version>
<version>2.1.0.RC1</version>
<relativePath>..</relativePath>
</parent>
<artifactId>spring-cloud-starter-openfeign</artifactId>