Compare commits
29
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4dd68ca2f2 | ||
|
|
af094d0bfc | ||
|
|
77cdd40f7d | ||
|
|
750cb35e6a | ||
|
|
b512c451fd | ||
|
|
da6a51778f | ||
|
|
9fc19bb6fe | ||
|
|
e0bf63bed1 | ||
|
|
a33fd6d869 | ||
|
|
06ccb9d1e5 | ||
|
|
d57cea265e | ||
|
|
34cb91bc4c | ||
|
|
58dc45d230 | ||
|
|
80af701ccf | ||
|
|
46bc5da424 | ||
|
|
7dcb696ec4 | ||
|
|
69461d4385 | ||
|
|
8364b16b8e | ||
|
|
6d4686624e | ||
|
|
51ad63231d | ||
|
|
6c09501d77 | ||
|
|
7e1c91c8b8 | ||
|
|
674b88b467 | ||
|
|
a57c416d4a | ||
|
|
ffd4290e06 | ||
|
|
804ef91620 | ||
|
|
48e2f70757 | ||
|
|
569628689b | ||
|
|
af02a8c692 |
+1
-1
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-openfeign</artifactId>
|
||||
<version>2.0.0.RC2</version>
|
||||
<version>2.0.2.RELEASE</version>
|
||||
</parent>
|
||||
<artifactId>spring-cloud-openfeign-docs</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
@@ -224,14 +224,14 @@ class FooController {
|
||||
private FooClient adminClient;
|
||||
|
||||
@Autowired
|
||||
public FooController(
|
||||
Decoder decoder, Encoder encoder, Client client, Contract contract) {
|
||||
public FooController(Decoder decoder, Encoder encoder, Client client, Contract contract) {
|
||||
this.fooClient = Feign.builder().client(client)
|
||||
.encoder(encoder)
|
||||
.decoder(decoder)
|
||||
.contract(contract)
|
||||
.contract(contract)
|
||||
.requestInterceptor(new BasicAuthRequestInterceptor("user", "user"))
|
||||
.target(FooClient.class, "http://PROD-SVC");
|
||||
|
||||
this.adminClient = Feign.builder().client(client)
|
||||
.encoder(encoder)
|
||||
.decoder(decoder)
|
||||
@@ -426,11 +426,3 @@ public class FooConfiguration {
|
||||
}
|
||||
}
|
||||
----
|
||||
OtherClass.someMethod(myprop.get());
|
||||
}
|
||||
}
|
||||
stripped). The proxy uses Ribbon to locate an instance to forward to
|
||||
via discovery, and all requests are executed in a
|
||||
<<hystrix-fallbacks-for-routes, hystrix command>>, so
|
||||
failures will show up in Hystrix metrics, and once the circuit is open
|
||||
the proxy will not try to contact the service.
|
||||
|
||||
@@ -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.0.RC2</version>
|
||||
<version>2.0.2.RELEASE</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.1.RELEASE</version>
|
||||
<version>2.0.4.RELEASE</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.0.RC2</spring-cloud-commons.version>
|
||||
<spring-cloud-netflix.version>2.0.0.RC2</spring-cloud-netflix.version>
|
||||
<spring-cloud-commons.version>2.0.2.RELEASE</spring-cloud-commons.version>
|
||||
<spring-cloud-netflix.version>2.0.2.RELEASE</spring-cloud-netflix.version>
|
||||
|
||||
<!-- Plugin versions -->
|
||||
<maven-compiler-plugin.version>3.6.1</maven-compiler-plugin.version>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-openfeign</artifactId>
|
||||
<version>2.0.0.RC2</version>
|
||||
<version>2.0.2.RELEASE</version>
|
||||
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<artifactId>spring-cloud-openfeign-core</artifactId>
|
||||
@@ -93,6 +93,10 @@
|
||||
<artifactId>feign-core</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.openfeign.form</groupId>
|
||||
<artifactId>feign-form-spring</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.openfeign</groupId>
|
||||
<artifactId>feign-slf4j</artifactId>
|
||||
@@ -163,6 +167,16 @@
|
||||
<artifactId>okhttp</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-autoconfigure-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
|
||||
+2
-2
@@ -202,8 +202,8 @@ public class FeignAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(Client.class)
|
||||
public Client feignClient() {
|
||||
return new OkHttpClient(this.okHttpClient);
|
||||
public Client feignClient(okhttp3.OkHttpClient client) {
|
||||
return new OkHttpClient(client);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+93
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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 org.springframework.context.ApplicationContext;
|
||||
|
||||
/**
|
||||
* A builder for creating Feign clients without using the {@link FeignClient} annotation.
|
||||
* <p>
|
||||
* This builder builds the Feign client exactly like it would be created by using the
|
||||
* {@link FeignClient} annotation.
|
||||
*
|
||||
* @author Sven Döring
|
||||
*/
|
||||
public class FeignClientBuilder {
|
||||
|
||||
private final ApplicationContext applicationContext;
|
||||
|
||||
public FeignClientBuilder(final ApplicationContext applicationContext) {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
public <T> Builder<T> forType(final Class<T> type, final String name) {
|
||||
return new Builder<>(applicationContext, type, name);
|
||||
}
|
||||
|
||||
public static class Builder<T> {
|
||||
|
||||
private FeignClientFactoryBean feignClientFactoryBean;
|
||||
|
||||
private Builder(final ApplicationContext applicationContext, final Class<T> type,
|
||||
final String name) {
|
||||
this.feignClientFactoryBean = new FeignClientFactoryBean();
|
||||
|
||||
this.feignClientFactoryBean.setApplicationContext(applicationContext);
|
||||
this.feignClientFactoryBean.setType(type);
|
||||
this.feignClientFactoryBean.setName(FeignClientsRegistrar.getName(name));
|
||||
// preset default values - these values resemble the default values on the
|
||||
// FeignClient annotation
|
||||
this.url("").path("").decode404(false).fallback(void.class)
|
||||
.fallbackFactory(void.class);
|
||||
}
|
||||
|
||||
public Builder url(final String url) {
|
||||
this.feignClientFactoryBean.setUrl(FeignClientsRegistrar.getUrl(url));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder path(final String path) {
|
||||
this.feignClientFactoryBean.setPath(FeignClientsRegistrar.getPath(path));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder decode404(final boolean decode404) {
|
||||
this.feignClientFactoryBean.setDecode404(decode404);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder fallback(final Class<T> fallback) {
|
||||
FeignClientsRegistrar.validateFallback(fallback);
|
||||
this.feignClientFactoryBean.setFallback(fallback);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder fallbackFactory(final Class<T> fallbackFactory) {
|
||||
FeignClientsRegistrar.validateFallbackFactory(fallbackFactory);
|
||||
this.feignClientFactoryBean.setFallbackFactory(fallbackFactory);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param <T> the target type of the Feign client to be created
|
||||
* @return the created Feign client
|
||||
*/
|
||||
public <T> T build() {
|
||||
return this.feignClientFactoryBean.getTarget();
|
||||
}
|
||||
}
|
||||
}
|
||||
+11
-3
@@ -229,6 +229,14 @@ class FeignClientFactoryBean implements FactoryBean<Object>, InitializingBean,
|
||||
|
||||
@Override
|
||||
public Object getObject() throws Exception {
|
||||
return getTarget();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param <T> the target type of the Feign client
|
||||
* @return a {@link Feign} client created with the specified data and the context information
|
||||
*/
|
||||
<T> T getTarget() {
|
||||
FeignContext context = applicationContext.getBean(FeignContext.class);
|
||||
Feign.Builder builder = feign(context);
|
||||
|
||||
@@ -241,7 +249,7 @@ class FeignClientFactoryBean implements FactoryBean<Object>, InitializingBean,
|
||||
url = this.name;
|
||||
}
|
||||
url += cleanPath();
|
||||
return loadBalance(builder, context, new HardCodedTarget<>(this.type,
|
||||
return (T) loadBalance(builder, context, new HardCodedTarget<>(this.type,
|
||||
this.name, url));
|
||||
}
|
||||
if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) {
|
||||
@@ -251,14 +259,14 @@ class FeignClientFactoryBean implements FactoryBean<Object>, InitializingBean,
|
||||
Client client = getOptional(context, Client.class);
|
||||
if (client != null) {
|
||||
if (client instanceof LoadBalancerFeignClient) {
|
||||
// not lod balancing because we have a url,
|
||||
// not load balancing because we have a url,
|
||||
// but ribbon is on the classpath, so unwrap
|
||||
client = ((LoadBalancerFeignClient)client).getDelegate();
|
||||
}
|
||||
builder.client(client);
|
||||
}
|
||||
Targeter targeter = get(context, Targeter.class);
|
||||
return targeter.target(this, builder, context, new HardCodedTarget<>(
|
||||
return (T) targeter.target(this, builder, context, new HardCodedTarget<>(
|
||||
this.type, this.name, url));
|
||||
}
|
||||
|
||||
|
||||
+22
-3
@@ -198,12 +198,19 @@ class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar,
|
||||
AnnotationAttributes annotation = AnnotationAttributes.fromMap(attributes);
|
||||
// This blows up if an aliased property is overspecified
|
||||
// FIXME annotation.getAliasedString("name", FeignClient.class, null);
|
||||
validateFallback(annotation.getClass("fallback"));
|
||||
validateFallbackFactory(annotation.getClass("fallbackFactory"));
|
||||
}
|
||||
|
||||
static void validateFallback(final Class clazz) {
|
||||
Assert.isTrue(
|
||||
!annotation.getClass("fallback").isInterface(),
|
||||
!clazz.isInterface(),
|
||||
"Fallback class must implement the interface annotated by @FeignClient"
|
||||
);
|
||||
Assert.isTrue(
|
||||
!annotation.getClass("fallbackFactory").isInterface(),
|
||||
}
|
||||
|
||||
static void validateFallbackFactory(final Class clazz) {
|
||||
Assert.isTrue(!clazz.isInterface(),
|
||||
"Fallback factory must produce instances of fallback classes that implement the interface annotated by @FeignClient"
|
||||
);
|
||||
}
|
||||
@@ -217,6 +224,10 @@ class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar,
|
||||
name = (String) attributes.get("value");
|
||||
}
|
||||
name = resolve(name);
|
||||
return getName(name);
|
||||
}
|
||||
|
||||
static String getName(String name) {
|
||||
if (!StringUtils.hasText(name)) {
|
||||
return "";
|
||||
}
|
||||
@@ -247,6 +258,10 @@ class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar,
|
||||
|
||||
private String getUrl(Map<String, Object> attributes) {
|
||||
String url = resolve((String) attributes.get("url"));
|
||||
return getUrl(url);
|
||||
}
|
||||
|
||||
static String getUrl(String url) {
|
||||
if (StringUtils.hasText(url) && !(url.startsWith("#{") && url.contains("}"))) {
|
||||
if (!url.contains("://")) {
|
||||
url = "http://" + url;
|
||||
@@ -263,6 +278,10 @@ class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar,
|
||||
|
||||
private String getPath(Map<String, Object> attributes) {
|
||||
String path = resolve((String) attributes.get("path"));
|
||||
return getPath(path);
|
||||
}
|
||||
|
||||
static String getPath(String path) {
|
||||
if (StringUtils.hasText(path)) {
|
||||
path = path.trim();
|
||||
if (!path.startsWith("/")) {
|
||||
|
||||
-13
@@ -62,19 +62,6 @@ class HystrixTargeter implements Targeter {
|
||||
Class<?> fallbackFactoryClass) {
|
||||
FallbackFactory<? extends T> fallbackFactory = (FallbackFactory<? extends T>)
|
||||
getFromContext("fallbackFactory", feignClientName, context, fallbackFactoryClass, FallbackFactory.class);
|
||||
/* We take a sample fallback from the fallback factory to check if it returns a fallback
|
||||
that is compatible with the annotated feign interface. */
|
||||
Object exampleFallback = fallbackFactory.create(new RuntimeException());
|
||||
Assert.notNull(exampleFallback,
|
||||
String.format(
|
||||
"Incompatible fallbackFactory instance for feign client %s. Factory may not produce null!",
|
||||
feignClientName));
|
||||
if (!target.type().isAssignableFrom(exampleFallback.getClass())) {
|
||||
throw new IllegalStateException(
|
||||
String.format(
|
||||
"Incompatible fallbackFactory instance for feign client %s. Factory produces instances of '%s', but should produce instances of '%s'",
|
||||
feignClientName, exampleFallback.getClass(), target.type()));
|
||||
}
|
||||
return builder.target(target, fallbackFactory);
|
||||
}
|
||||
|
||||
|
||||
+1
-2
@@ -79,9 +79,8 @@ public class FeignContentGzipEncodingInterceptor extends BaseRequestInterceptor
|
||||
final long length = Long.parseLong(strLen);
|
||||
return length > getProperties().getMinRequestSize();
|
||||
} catch (NumberFormatException ex) {
|
||||
// ignores the exception
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+2
@@ -54,6 +54,7 @@ public class FeignRibbonClientAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnMissingClass("org.springframework.retry.support.RetryTemplate")
|
||||
public CachingSpringLoadBalancerFactory cachingLBClientFactory(
|
||||
SpringClientFactory factory) {
|
||||
@@ -62,6 +63,7 @@ public class FeignRibbonClientAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnClass(name = "org.springframework.retry.support.RetryTemplate")
|
||||
public CachingSpringLoadBalancerFactory retryabeCachingLBClientFactory(
|
||||
SpringClientFactory factory,
|
||||
|
||||
+7
-1
@@ -97,7 +97,13 @@ public class LoadBalancerFeignClient implements Client {
|
||||
}
|
||||
|
||||
static URI cleanUrl(String originalUrl, String host) {
|
||||
return URI.create(originalUrl.replaceFirst(host, ""));
|
||||
String newUrl = originalUrl.replaceFirst(host, "");
|
||||
StringBuffer buffer = new StringBuffer(newUrl);
|
||||
if((newUrl.startsWith("https://") && newUrl.length() == 8) ||
|
||||
(newUrl.startsWith("http://") && newUrl.length() == 7)) {
|
||||
buffer.append("/");
|
||||
}
|
||||
return URI.create(buffer.toString());
|
||||
}
|
||||
|
||||
private FeignLoadBalancer lbClient(String clientName) {
|
||||
|
||||
+17
@@ -24,6 +24,7 @@ import java.lang.reflect.Type;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collection;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
@@ -35,10 +36,12 @@ import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.ByteArrayHttpMessageConverter;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.protobuf.ProtobufHttpMessageConverter;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import feign.RequestTemplate;
|
||||
import feign.codec.EncodeException;
|
||||
import feign.codec.Encoder;
|
||||
import feign.form.spring.SpringFormEncoder;
|
||||
|
||||
import static org.springframework.cloud.openfeign.support.FeignUtils.getHeaders;
|
||||
import static org.springframework.cloud.openfeign.support.FeignUtils.getHttpHeaders;
|
||||
@@ -51,6 +54,8 @@ public class SpringEncoder implements Encoder {
|
||||
|
||||
private static final Log log = LogFactory.getLog(SpringEncoder.class);
|
||||
|
||||
private final SpringFormEncoder springFormEncoder = new SpringFormEncoder();
|
||||
|
||||
private ObjectFactory<HttpMessageConverters> messageConverters;
|
||||
|
||||
public SpringEncoder(ObjectFactory<HttpMessageConverters> messageConverters) {
|
||||
@@ -71,6 +76,18 @@ public class SpringEncoder implements Encoder {
|
||||
requestContentType = MediaType.valueOf(type);
|
||||
}
|
||||
|
||||
if (bodyType != null && bodyType.equals(MultipartFile.class)) {
|
||||
if (Objects.equals(requestContentType, MediaType.MULTIPART_FORM_DATA)) {
|
||||
springFormEncoder.encode(requestBody, bodyType, request);
|
||||
return;
|
||||
} else {
|
||||
String message = "Content-Type \"" + MediaType.MULTIPART_FORM_DATA +
|
||||
"\" not set for request body of type " +
|
||||
requestBody.getClass().getSimpleName();
|
||||
throw new EncodeException(message);
|
||||
}
|
||||
}
|
||||
|
||||
for (HttpMessageConverter<?> messageConverter : this.messageConverters
|
||||
.getObject().getConverters()) {
|
||||
if (messageConverter.canWrite(requestType, requestContentType)) {
|
||||
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
{"groups": [
|
||||
], "properties": [
|
||||
{
|
||||
"name": "feign.hystrix.enabled",
|
||||
"type": "java.lang.Boolean",
|
||||
"description": "If true, an OpenFeign client will be wrapped with a Hystrix circuit breaker.",
|
||||
"defaultValue": "false"
|
||||
},
|
||||
{
|
||||
"name": "feign.httpclient.enabled",
|
||||
"type": "java.lang.Boolean",
|
||||
"description": "Enables the use of the Apache HTTP Client by Feign.",
|
||||
"defaultValue": "true"
|
||||
},
|
||||
{
|
||||
"name": "feign.okhttp.enabled",
|
||||
"type": "java.lang.Boolean",
|
||||
"description": "Enables the use of the OK HTTP Client by Feign.",
|
||||
"defaultValue": "false"
|
||||
},
|
||||
{
|
||||
"name": "feign.compression.response.enabled",
|
||||
"type": "java.lang.Boolean",
|
||||
"description": "Enables the response from Feign to be compressed.",
|
||||
"defaultValue": "false"
|
||||
},
|
||||
{
|
||||
"name": "feign.compression.request.enabled",
|
||||
"type": "java.lang.Boolean",
|
||||
"description": "Enables the request sent by Feign to be compressed.",
|
||||
"defaultValue": "false"
|
||||
}
|
||||
]}
|
||||
+158
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* 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 java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.file.ClosedFileSystemException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.cloud.openfeign.testclients.TestClient;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* @author Sven Döring
|
||||
*/
|
||||
public class FeignClientBuilderTests {
|
||||
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
private FeignClientBuilder feignClientBuilder;
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
private static Object getDefaultValueFromFeignClientAnnotation(
|
||||
final String methodName) {
|
||||
final Method method = ReflectionUtils.findMethod(FeignClient.class, methodName);
|
||||
return method.getDefaultValue();
|
||||
}
|
||||
|
||||
private static void assertFactoryBeanField(final FeignClientBuilder.Builder builder,
|
||||
final String fieldName, final Object expectedValue) {
|
||||
final Field factoryBeanField = ReflectionUtils
|
||||
.findField(FeignClientBuilder.Builder.class, "feignClientFactoryBean");
|
||||
ReflectionUtils.makeAccessible(factoryBeanField);
|
||||
final FeignClientFactoryBean factoryBean = (FeignClientFactoryBean) ReflectionUtils
|
||||
.getField(factoryBeanField, builder);
|
||||
|
||||
final Field field = ReflectionUtils.findField(FeignClientFactoryBean.class,
|
||||
fieldName);
|
||||
ReflectionUtils.makeAccessible(field);
|
||||
final Object value = ReflectionUtils.getField(field, factoryBean);
|
||||
Assert.assertEquals("Expected value for the field '" + fieldName + "':",
|
||||
expectedValue, value);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
this.applicationContext = Mockito.mock(ApplicationContext.class);
|
||||
this.feignClientBuilder = new FeignClientBuilder(applicationContext);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void safetyCheckForNewFieldsOnTheFeignClientAnnotation() {
|
||||
final List<String> methodNames = new ArrayList();
|
||||
for (final Method method : FeignClient.class.getMethods()) {
|
||||
methodNames.add(method.getName());
|
||||
}
|
||||
methodNames.removeAll(
|
||||
Arrays.asList("annotationType", "value", "serviceId", "qualifier",
|
||||
"configuration", "primary", "equals", "hashCode", "toString"));
|
||||
Collections.sort(methodNames);
|
||||
// If this safety check fails the Builder has to be updated.
|
||||
// (1) Either a field was removed from the FeignClient annotation and so it has to
|
||||
// be removed
|
||||
// on this builder class.
|
||||
// (2) Or a new field was added and the builder class has to be extended with this
|
||||
// new field.
|
||||
Assert.assertThat(methodNames, Matchers.contains("decode404", "fallback",
|
||||
"fallbackFactory", "name", "path", "url"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forType_preinitializedBuilder() {
|
||||
// when:
|
||||
final FeignClientBuilder.Builder builder = feignClientBuilder
|
||||
.forType(FeignClientBuilderTests.class, "TestClient");
|
||||
|
||||
// then:
|
||||
assertFactoryBeanField(builder, "applicationContext", applicationContext);
|
||||
assertFactoryBeanField(builder, "type", FeignClientBuilderTests.class);
|
||||
assertFactoryBeanField(builder, "name", "TestClient");
|
||||
|
||||
// and:
|
||||
assertFactoryBeanField(builder, "url",
|
||||
getDefaultValueFromFeignClientAnnotation("url"));
|
||||
assertFactoryBeanField(builder, "path",
|
||||
getDefaultValueFromFeignClientAnnotation("path"));
|
||||
assertFactoryBeanField(builder, "decode404",
|
||||
getDefaultValueFromFeignClientAnnotation("decode404"));
|
||||
assertFactoryBeanField(builder, "fallback",
|
||||
getDefaultValueFromFeignClientAnnotation("fallback"));
|
||||
assertFactoryBeanField(builder, "fallbackFactory",
|
||||
getDefaultValueFromFeignClientAnnotation("fallbackFactory"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forType_allFieldsSetOnBuilder() {
|
||||
// when:
|
||||
final FeignClientBuilder.Builder builder = feignClientBuilder
|
||||
.forType(FeignClientBuilderTests.class, "TestClient").decode404(true)
|
||||
.fallback(Object.class).fallbackFactory(Object.class).path("Path/")
|
||||
.url("Url/");
|
||||
|
||||
// then:
|
||||
assertFactoryBeanField(builder, "applicationContext", applicationContext);
|
||||
assertFactoryBeanField(builder, "type", FeignClientBuilderTests.class);
|
||||
assertFactoryBeanField(builder, "name", "TestClient");
|
||||
|
||||
// and:
|
||||
assertFactoryBeanField(builder, "url", "http://Url/");
|
||||
assertFactoryBeanField(builder, "path", "/Path");
|
||||
assertFactoryBeanField(builder, "decode404", true);
|
||||
assertFactoryBeanField(builder, "fallback", Object.class);
|
||||
assertFactoryBeanField(builder, "fallbackFactory", Object.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forType_build() {
|
||||
// given:
|
||||
Mockito.when(applicationContext.getBean(FeignContext.class))
|
||||
.thenThrow(new ClosedFileSystemException()); // throw an unusual exception
|
||||
// in the
|
||||
// FeignClientFactoryBean
|
||||
final FeignClientBuilder.Builder builder = feignClientBuilder
|
||||
.forType(TestClient.class, "TestClient");
|
||||
|
||||
// expect: 'the build will fail right after calling build() with the mocked
|
||||
// unusual exception'
|
||||
thrown.expect(Matchers.isA(ClosedFileSystemException.class));
|
||||
builder.build();
|
||||
}
|
||||
}
|
||||
+35
-2
@@ -31,8 +31,11 @@ import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.cloud.openfeign.FeignClientBuilder;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
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,12 +69,24 @@ public class FeignClientTests {
|
||||
@Autowired
|
||||
private org.springframework.cloud.openfeign.beans.extra.TestClient extraClient;
|
||||
|
||||
@Qualifier("build-by-builder")
|
||||
@Autowired
|
||||
private TestClient buildByBuilder;
|
||||
|
||||
@Configuration
|
||||
@EnableAutoConfiguration
|
||||
@RestController
|
||||
@EnableFeignClients
|
||||
@Import(FeignClientBuilder.class)
|
||||
protected static class Application {
|
||||
|
||||
@Bean("build-by-builder")
|
||||
public TestClient buildByBuilder(final FeignClientBuilder feignClientBuilder) {
|
||||
return feignClientBuilder
|
||||
.forType(TestClient.class, "builderapp")
|
||||
.build();
|
||||
}
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET, value = "/hello")
|
||||
public Hello getHello() {
|
||||
return new Hello("hello world 1");
|
||||
@@ -112,7 +127,7 @@ public class FeignClientTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAnnnotations() throws Exception {
|
||||
public void testAnnotations() {
|
||||
Map<String, Object> beans = this.context
|
||||
.getBeansWithAnnotation(FeignClient.class);
|
||||
assertTrue("Wrong clients: " + beans,
|
||||
@@ -122,13 +137,31 @@ public class FeignClientTests {
|
||||
@Test
|
||||
public void testClient() {
|
||||
assertNotNull("testClient was null", this.testClient);
|
||||
assertNotNull("testClient was null", this.extraClient);
|
||||
assertNotNull("extraClient was null", this.extraClient);
|
||||
assertTrue("testClient is not a java Proxy",
|
||||
Proxy.isProxyClass(this.testClient.getClass()));
|
||||
InvocationHandler invocationHandler = Proxy.getInvocationHandler(this.testClient);
|
||||
assertNotNull("invocationHandler was null", invocationHandler);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void extraClient() {
|
||||
assertNotNull("extraClient was null", this.extraClient);
|
||||
assertTrue("extraClient is not a java Proxy",
|
||||
Proxy.isProxyClass(this.extraClient.getClass()));
|
||||
InvocationHandler invocationHandler = Proxy.getInvocationHandler(this.extraClient);
|
||||
assertNotNull("invocationHandler was null", invocationHandler);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void buildByBuilder() {
|
||||
assertNotNull("buildByBuilder was null", this.buildByBuilder);
|
||||
assertTrue("buildByBuilder is not a java Proxy",
|
||||
Proxy.isProxyClass(this.buildByBuilder.getClass()));
|
||||
InvocationHandler invocationHandler = Proxy.getInvocationHandler(this.buildByBuilder);
|
||||
assertNotNull("invocationHandler was null", invocationHandler);
|
||||
}
|
||||
|
||||
@Configuration
|
||||
public static class TestDefaultFeignConfig {
|
||||
}
|
||||
|
||||
+2
@@ -18,9 +18,11 @@ package org.springframework.cloud.openfeign.beans;
|
||||
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.cloud.openfeign.beans.FeignClientTests.Hello;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
|
||||
@Primary
|
||||
@FeignClient(value = "localapp")
|
||||
public interface TestClient {
|
||||
@RequestMapping(method = RequestMethod.GET, value = "/hello")
|
||||
|
||||
-40
@@ -240,44 +240,4 @@ public class FeignClientValidationTests {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrongFallbackFactoryGenericType() {
|
||||
try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
|
||||
WrongFallbackFactoryGenericTypeConfiguration.class)) {
|
||||
this.expected.expectMessage("Incompatible fallbackFactory instance");
|
||||
assertNotNull(context.getBean(WrongFallbackFactoryGenericTypeConfiguration.Client.class));
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@Import(FeignAutoConfiguration.class)
|
||||
@EnableFeignClients(clients = WrongFallbackFactoryGenericTypeConfiguration.Client.class)
|
||||
protected static class WrongFallbackFactoryGenericTypeConfiguration {
|
||||
|
||||
@FeignClient(name = "foobar", url = "http://localhost", fallbackFactory = ClientFallback.class)
|
||||
interface Client {
|
||||
@RequestMapping(method = RequestMethod.GET, value = "/")
|
||||
String get();
|
||||
}
|
||||
|
||||
@Bean
|
||||
ClientFallback dummy() {
|
||||
return new ClientFallback();
|
||||
}
|
||||
|
||||
class ClientFallback implements FallbackFactory<String> {
|
||||
|
||||
@Override
|
||||
public String create(Throwable cause) {
|
||||
return "tryinToTrickYa";
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
public Feign.Builder feignBuilder() {
|
||||
return HystrixFeign.builder();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+16
-4
@@ -37,7 +37,9 @@ import org.springframework.cloud.netflix.ribbon.SpringClientFactory;
|
||||
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.hamcrest.MockitoHamcrest.argThat;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
@@ -87,14 +89,24 @@ public class FeignRibbonClientTests {
|
||||
when(stats.getSingleServerStat(any(Server.class))).thenReturn(mock(ServerStats.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void remoteRequestIsSentAtRoot() throws Exception {
|
||||
Request request = new RequestTemplate().method("GET").append("http://foo")
|
||||
.request();
|
||||
this.client.execute(request, new Options());
|
||||
RequestMatcher matcher = new RequestMatcher("http://foo.com:8000/");
|
||||
verify(this.delegate).execute(argThat(matcher),
|
||||
any(Options.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void remoteRequestIsSent() throws Exception {
|
||||
Request request = new RequestTemplate().method("GET").append("http://foo/")
|
||||
.request();
|
||||
this.client.execute(request, new Options());
|
||||
RequestMatcher matcher = new RequestMatcher("http://foo.com:8000/");
|
||||
/*FIXME verify(this.delegate).execute(argThat(matcher),
|
||||
any(Options.class));*/
|
||||
verify(this.delegate).execute(argThat(matcher),
|
||||
any(Options.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -103,8 +115,8 @@ public class FeignRibbonClientTests {
|
||||
.request();
|
||||
this.client.execute(request, new Options());
|
||||
RequestMatcher matcher = new RequestMatcher("https://foo.com:8000/");
|
||||
/*FIXME verify(this.delegate).execute(argThat(matcher),
|
||||
any(Options.class));*/
|
||||
verify(this.delegate).execute(argThat(matcher),
|
||||
any(Options.class));
|
||||
}
|
||||
|
||||
private final static class RequestMatcher extends CustomMatcher<Request> {
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
package org.springframework.cloud.netflix.feign.ribbon;
|
||||
package org.springframework.cloud.openfeign.ribbon;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import javax.net.ssl.SSLContextSpi;
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*
|
||||
*/
|
||||
package org.springframework.cloud.netflix.feign.ribbon;
|
||||
package org.springframework.cloud.openfeign.ribbon;
|
||||
|
||||
import okhttp3.OkHttpClient;
|
||||
|
||||
|
||||
+28
@@ -40,9 +40,11 @@ import org.springframework.http.converter.AbstractGenericHttpMessageConverter;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||
import org.springframework.http.converter.HttpMessageNotWritableException;
|
||||
import org.springframework.mock.web.MockMultipartFile;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
@@ -50,6 +52,7 @@ import static org.hamcrest.Matchers.nullValue;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import feign.RequestTemplate;
|
||||
import feign.codec.EncodeException;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
@@ -97,6 +100,31 @@ public class SpringEncoderTests {
|
||||
assertThat("request charset is not null", request.charset(), is(nullValue()));
|
||||
}
|
||||
|
||||
@Test(expected = EncodeException.class)
|
||||
public void testMultipartFile1() {
|
||||
SpringEncoder encoder = this.context.getInstance("foo", SpringEncoder.class);
|
||||
assertThat(encoder, is(notNullValue()));
|
||||
RequestTemplate request = new RequestTemplate();
|
||||
|
||||
MultipartFile multipartFile = new MockMultipartFile("test_multipart_file", "hi".getBytes());
|
||||
encoder.encode(multipartFile, MultipartFile.class, request);
|
||||
|
||||
assertThat("request charset is not null", request.charset(), is(nullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultipartFile2() {
|
||||
SpringEncoder encoder = this.context.getInstance("foo", SpringEncoder.class);
|
||||
assertThat(encoder, is(notNullValue()));
|
||||
RequestTemplate request = new RequestTemplate();
|
||||
request = request.header("Content-Type", MediaType.MULTIPART_FORM_DATA_VALUE);
|
||||
|
||||
MultipartFile multipartFile = new MockMultipartFile("test_multipart_file", "hi".getBytes());
|
||||
encoder.encode(multipartFile, MultipartFile.class, request);
|
||||
|
||||
assertThat("request charset is not null", request.charset(), is(nullValue()));
|
||||
}
|
||||
|
||||
class MediaTypeMatcher implements ArgumentMatcher<MediaType> {
|
||||
|
||||
private MediaType mediaType;
|
||||
|
||||
+62
-2
@@ -66,6 +66,7 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
import com.netflix.hystrix.HystrixCommand;
|
||||
import com.netflix.hystrix.HystrixCommandGroupKey;
|
||||
import com.netflix.hystrix.HystrixCommandKey;
|
||||
import com.netflix.hystrix.exception.HystrixRuntimeException;
|
||||
import com.netflix.loadbalancer.Server;
|
||||
import com.netflix.loadbalancer.ServerList;
|
||||
|
||||
@@ -129,6 +130,12 @@ public class FeignClientTests {
|
||||
@Autowired
|
||||
private HystrixClientWithFallBackFactory hystrixClientWithFallBackFactory;
|
||||
|
||||
@Autowired
|
||||
private InvalidTypeHystrixClientWithFallBackFactory invalidTypeHystrixClientWithFallBackFactory;
|
||||
|
||||
@Autowired
|
||||
private NullHystrixClientWithFallBackFactory nullHystrixClientWithFallBackFactory;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("localapp3FeignClient")
|
||||
HystrixClient namedHystrixClient;
|
||||
@@ -275,6 +282,20 @@ public class FeignClientTests {
|
||||
Hello fail();
|
||||
}
|
||||
|
||||
@FeignClient(name = "localapp6", fallbackFactory = InvalidTypeHystrixClientFallbackFactory.class)
|
||||
protected interface InvalidTypeHystrixClientWithFallBackFactory {
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET, path = "/fail")
|
||||
Hello fail();
|
||||
}
|
||||
|
||||
@FeignClient(name = "localapp7", fallbackFactory = NullHystrixClientFallbackFactory.class)
|
||||
protected interface NullHystrixClientWithFallBackFactory {
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET, path = "/fail")
|
||||
Hello fail();
|
||||
}
|
||||
|
||||
static class HystrixClientFallbackFactory implements FallbackFactory<HystrixClientWithFallBackFactory> {
|
||||
|
||||
@Override
|
||||
@@ -289,6 +310,22 @@ public class FeignClientTests {
|
||||
}
|
||||
}
|
||||
|
||||
static class InvalidTypeHystrixClientFallbackFactory implements FallbackFactory<String> {
|
||||
|
||||
@Override
|
||||
public String create(final Throwable cause) {
|
||||
return "hello";
|
||||
}
|
||||
}
|
||||
|
||||
static class NullHystrixClientFallbackFactory implements FallbackFactory<String> {
|
||||
|
||||
@Override
|
||||
public String create(final Throwable cause) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static class HystrixClientFallback implements HystrixClient {
|
||||
@Override
|
||||
public Hello fail() {
|
||||
@@ -348,7 +385,8 @@ public class FeignClientTests {
|
||||
@RestController
|
||||
@EnableFeignClients(clients = { TestClientServiceId.class, TestClient.class,
|
||||
DecodingTestClient.class, HystrixClient.class, HystrixClientWithFallBackFactory.class,
|
||||
HystrixSetterFactoryClient.class},
|
||||
HystrixSetterFactoryClient.class, InvalidTypeHystrixClientWithFallBackFactory.class,
|
||||
NullHystrixClientWithFallBackFactory.class},
|
||||
defaultConfiguration = TestDefaultFeignConfig.class)
|
||||
@RibbonClients({
|
||||
@RibbonClient(name = "localapp", configuration = LocalRibbonClientConfiguration.class),
|
||||
@@ -356,7 +394,9 @@ public class FeignClientTests {
|
||||
@RibbonClient(name = "localapp2", configuration = LocalRibbonClientConfiguration.class),
|
||||
@RibbonClient(name = "localapp3", configuration = LocalRibbonClientConfiguration.class),
|
||||
@RibbonClient(name = "localapp4", configuration = LocalRibbonClientConfiguration.class),
|
||||
@RibbonClient(name = "localapp5", configuration = LocalRibbonClientConfiguration.class)
|
||||
@RibbonClient(name = "localapp5", configuration = LocalRibbonClientConfiguration.class),
|
||||
@RibbonClient(name = "localapp6", configuration = LocalRibbonClientConfiguration.class),
|
||||
@RibbonClient(name = "localapp7", configuration = LocalRibbonClientConfiguration.class)
|
||||
})
|
||||
protected static class Application {
|
||||
|
||||
@@ -371,6 +411,16 @@ public class FeignClientTests {
|
||||
return new HystrixClientFallbackFactory();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public InvalidTypeHystrixClientFallbackFactory invalidTypeHystrixClientFallbackFactory() {
|
||||
return new InvalidTypeHystrixClientFallbackFactory();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public NullHystrixClientFallbackFactory nullHystrixClientFallbackFactory() {
|
||||
return new NullHystrixClientFallbackFactory();
|
||||
}
|
||||
|
||||
@Bean
|
||||
FeignFormatterRegistrar feignFormatterRegistrar() {
|
||||
return new FeignFormatterRegistrar() {
|
||||
@@ -722,6 +772,16 @@ public class FeignClientTests {
|
||||
hello.getMessage().contains("500"));
|
||||
}
|
||||
|
||||
@Test(expected = HystrixRuntimeException.class)
|
||||
public void testInvalidTypeHystrixFallbackFactory() throws Exception {
|
||||
invalidTypeHystrixClientWithFallBackFactory.fail();
|
||||
}
|
||||
|
||||
@Test(expected = HystrixRuntimeException.class)
|
||||
public void testNullHystrixFallbackFactory() throws Exception {
|
||||
nullHystrixClientWithFallBackFactory.fail();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void namedFeignClientWorks() {
|
||||
assertNotNull("namedHystrixClient was null", this.namedHystrixClient);
|
||||
|
||||
@@ -5,16 +5,17 @@
|
||||
<parent>
|
||||
<artifactId>spring-cloud-dependencies-parent</artifactId>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<version>2.0.1.RELEASE</version>
|
||||
<version>2.0.4.RELEASE</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
<artifactId>spring-cloud-openfeign-dependencies</artifactId>
|
||||
<version>2.0.0.RC2</version>
|
||||
<version>2.0.2.RELEASE</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>spring-cloud-openfeign-dependencies</name>
|
||||
<description>Spring Cloud OpenFeign Dependencies</description>
|
||||
<properties>
|
||||
<feign.version>9.5.1</feign.version>
|
||||
<feign.version>9.7.0</feign.version>
|
||||
<feign-form.version>3.3.0</feign-form.version>
|
||||
</properties>
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
@@ -33,6 +34,11 @@
|
||||
<artifactId>feign-core</artifactId>
|
||||
<version>${feign.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.openfeign.form</groupId>
|
||||
<artifactId>feign-form-spring</artifactId>
|
||||
<version>${feign-form.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.github.openfeign</groupId>
|
||||
<artifactId>feign-slf4j</artifactId>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-openfeign</artifactId>
|
||||
<version>2.0.0.RC2</version>
|
||||
<version>2.0.2.RELEASE</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
@@ -54,10 +54,12 @@
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-netflix-archaius</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
Reference in New Issue
Block a user