Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
48bb0cdba5 | ||
|
|
dc5eef0125 | ||
|
|
343f436b71 | ||
|
|
d3da7e16e8 | ||
|
|
f184c3f293 | ||
|
|
4e89dd1523 | ||
|
|
f600140004 | ||
|
|
63ba4d40ff | ||
|
|
d07c229b0e | ||
|
|
06862ab090 | ||
|
|
84cb74a898 | ||
|
|
72784920d8 | ||
|
|
9677353c27 | ||
|
|
4766d95def | ||
|
|
bba3f2e92c | ||
|
|
c4fd4eb42e | ||
|
|
b56a4a1259 | ||
|
|
4a4da0e2d1 | ||
|
|
bf13ae95c9 | ||
|
|
efca091fda | ||
|
|
af06086c30 | ||
|
|
5497f5a37c | ||
|
|
2e2987e787 | ||
|
|
12084de3a9 | ||
|
|
7cd7ed5c70 | ||
|
|
5a6a75d22b | ||
|
|
a790386732 | ||
|
|
84cf97b391 | ||
|
|
fa5162c2fc | ||
|
|
3002643ee7 | ||
|
|
b1ec55cb01 | ||
|
|
f0e0e7ea64 |
+2
-1
@@ -4,6 +4,7 @@ Manual changes to this file will be lost when it is generated again.
|
||||
Edit the files in the src/main/asciidoc/ directory instead.
|
||||
////
|
||||
|
||||
|
||||
image:https://circleci.com/gh/spring-cloud/spring-cloud-openfeign.svg?style=svg["CircleCI", link="https://circleci.com/gh/spring-cloud/spring-cloud-openfeign"]
|
||||
|
||||
image:https://codecov.io/gh/spring-cloud/spring-cloud-openfeign/branch/master/graph/badge.svg["Codecov", link="https://codecov.io/gh/spring-cloud/spring-cloud-openfeign"]
|
||||
@@ -312,4 +313,4 @@ Go to `File` -> `Settings` -> `Other settings` -> `Checkstyle`. There click on t
|
||||
- `checkstyle.suppressions.file` - default suppressions. Please point it to the Spring Cloud Build's, `spring-cloud-build-tools/src/checkstyle/checkstyle-suppressions.xml` file either in your cloned repo or via the `https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-build-tools/src/checkstyle/checkstyle-suppressions.xml` URL.
|
||||
- `checkstyle.additional.suppressions.file` - this variable corresponds to suppressions in your local project. E.g. you're working on `spring-cloud-contract`. Then point to the `project-root/src/checkstyle/checkstyle-suppressions.xml` folder. Example for `spring-cloud-contract` would be: `/home/username/spring-cloud-contract/src/checkstyle/checkstyle-suppressions.xml`.
|
||||
|
||||
IMPORTANT: Remember to set the `Scan Scope` to `All sources` since we apply checkstyle rules for production and test sources.
|
||||
IMPORTANT: Remember to set the `Scan Scope` to `All sources` since we apply checkstyle rules for production and test sources.
|
||||
|
||||
+3
-11
@@ -6,16 +6,15 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-openfeign</artifactId>
|
||||
<version>3.0.0-M2</version>
|
||||
<version>3.0.0-M3</version>
|
||||
</parent>
|
||||
<artifactId>spring-cloud-openfeign-docs</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<packaging>jar</packaging>
|
||||
<name>Spring Cloud OpenFeign Docs</name>
|
||||
<description>Spring Cloud Docs</description>
|
||||
<properties>
|
||||
<docs.main>spring-cloud-openfeign</docs.main>
|
||||
<main.basedir>${basedir}/..</main.basedir>
|
||||
<docs.whitelisted.branches>2.1.x,2.2.x</docs.whitelisted.branches>
|
||||
<configprops.inclusionPattern>feign.*</configprops.inclusionPattern>
|
||||
<upload-docs-zip.phase>deploy</upload-docs-zip.phase>
|
||||
</properties>
|
||||
@@ -26,14 +25,7 @@
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<sourceDirectory>src/main/asciidoc</sourceDirectory>
|
||||
</build>
|
||||
<profiles>
|
||||
<profile>
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
|===
|
||||
|Name | Default | Description
|
||||
|
||||
|feign.client.config | | null
|
||||
|feign.client.default-config | default | null
|
||||
|feign.client.default-to-properties | true | null
|
||||
|feign.client.config | |
|
||||
|feign.client.default-config | default |
|
||||
|feign.client.default-to-properties | true |
|
||||
|feign.compression.request.enabled | false | Enables the request sent by Feign to be compressed.
|
||||
|feign.compression.request.mime-types | [text/xml, application/xml, application/json] | The list of supported mime types.
|
||||
|feign.compression.request.min-request-size | 2048 | The minimum threshold content size.
|
||||
|feign.compression.response.enabled | false | Enables the response from Feign to be compressed.
|
||||
|feign.compression.response.useGzipDecoder | false | Enables the default gzip decoder to be used.
|
||||
|feign.httpclient.connection-timeout | 2000 | null
|
||||
|feign.httpclient.connection-timer-repeat | 3000 | null
|
||||
|feign.httpclient.disable-ssl-validation | false | null
|
||||
|feign.httpclient.connection-timeout | 2000 |
|
||||
|feign.httpclient.connection-timer-repeat | 3000 |
|
||||
|feign.httpclient.disable-ssl-validation | false |
|
||||
|feign.httpclient.enabled | true | Enables the use of the Apache HTTP Client by Feign.
|
||||
|feign.httpclient.follow-redirects | true | null
|
||||
|feign.httpclient.max-connections | 200 | null
|
||||
|feign.httpclient.max-connections-per-route | 50 | null
|
||||
|feign.httpclient.time-to-live | 900 | null
|
||||
|feign.httpclient.time-to-live-unit | | null
|
||||
|feign.httpclient.follow-redirects | true |
|
||||
|feign.httpclient.max-connections | 200 |
|
||||
|feign.httpclient.max-connections-per-route | 50 |
|
||||
|feign.httpclient.time-to-live | 900 |
|
||||
|feign.httpclient.time-to-live-unit | |
|
||||
|feign.hystrix.enabled | false | If true, an OpenFeign client will be wrapped with a Hystrix circuit breaker.
|
||||
|feign.okhttp.enabled | false | Enables the use of the OK HTTP Client by Feign.
|
||||
|
||||
|
||||
@@ -118,6 +118,8 @@ Spring Cloud OpenFeign provides the following beans by default for feign (`BeanT
|
||||
* `Client` feignClient: if Spring Cloud LoadBalancer is in the classpath, `FeignBlockingLoadBalancerClient` is used.
|
||||
If none of them is in the classpath, the default feign client is used.
|
||||
|
||||
NOTE: `spring-cloud-starter-openfeign` supports `spring-cloud-starter-loadbalancer`. However, as is an optional dependency, you need to make sure it been added to your project if you want to use it.
|
||||
|
||||
The OkHttpClient and ApacheHttpClient feign clients can be used by setting `feign.okhttp.enabled` or `feign.httpclient.enabled` to `true`, respectively, and having them on the classpath.
|
||||
You can customize the HTTP client used by providing a bean of either `org.apache.http.impl.client.CloseableHttpClient` when using Apache or `okhttp3.OkHttpClient` when using OK HTTP.
|
||||
|
||||
@@ -131,6 +133,10 @@ Spring Cloud OpenFeign _does not_ provide the following beans by default for fei
|
||||
* `SetterFactory`
|
||||
* `QueryMapEncoder`
|
||||
|
||||
A bean of `Retryer.NEVER_RETRY` with the type `Retryer` is created by default, which will disable retrying.
|
||||
Notice this retrying behavior is different from the Feign default one, where it will automatically retry IOExceptions,
|
||||
treating them as transient network related exceptions, and any RetryableException thrown from an ErrorDecoder.
|
||||
|
||||
Creating a bean of one of those type and placing it in a `@FeignClient` configuration (such as `FooConfiguration` above) allows you to override each one of the beans described. Example:
|
||||
|
||||
[source,java,indent=0]
|
||||
@@ -576,6 +582,25 @@ public interface DemoTemplate {
|
||||
}
|
||||
----
|
||||
|
||||
=== Feign `CollectionFormat` support
|
||||
We support `feign.CollectionFormat` by providing the `@CollectionFormat` annotation. You can annotate a Feign client method with it by passing the desired `feign.CollectionFormat` as annotation value.
|
||||
|
||||
In the following example, the `CSV` format is used instead of the default `EXPLODED` to process the method.
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@FeignClient(name = "demo")
|
||||
protected interface PageableFeignClient {
|
||||
|
||||
@CollectionFormat(feign.CollectionFormat.CSV)
|
||||
@GetMapping(path = "/page")
|
||||
ResponseEntity performRequest(Pageable page);
|
||||
|
||||
}
|
||||
----
|
||||
|
||||
TIP: Set the `CSV` format while sending `Pageable` as a query parameter in order for it to be encoded correctly.
|
||||
|
||||
=== Reactive Support
|
||||
As the https://github.com/OpenFeign/feign[OpenFeign project] does not currently support reactive clients, such as https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/web/reactive/function/client/WebClient.html[Spring WebClient], neither does Spring Cloud OpenFeign. We will add support for it here as soon as it becomes available in the core project.
|
||||
|
||||
|
||||
@@ -4,14 +4,14 @@
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>spring-cloud-openfeign</artifactId>
|
||||
<version>3.0.0-M2</version>
|
||||
<version>3.0.0-M3</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>3.0.0-M2</version>
|
||||
<version>3.0.0-M3</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
<scm>
|
||||
@@ -26,7 +26,7 @@
|
||||
<properties>
|
||||
<main.basedir>${basedir}</main.basedir>
|
||||
<jackson.version>2.7.3</jackson.version>
|
||||
<spring-cloud-commons.version>3.0.0-M2</spring-cloud-commons.version>
|
||||
<spring-cloud-commons.version>3.0.0-M3</spring-cloud-commons.version>
|
||||
|
||||
<!-- Plugin versions -->
|
||||
<maven-compiler-plugin.version>3.6.1</maven-compiler-plugin.version>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-openfeign</artifactId>
|
||||
<version>3.0.0-M2</version>
|
||||
<version>3.0.0-M3</version>
|
||||
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<artifactId>spring-cloud-openfeign-core</artifactId>
|
||||
@@ -134,6 +134,11 @@
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.vintage</groupId>
|
||||
<artifactId>junit-vintage-engine</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-test-support</artifactId>
|
||||
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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
|
||||
*
|
||||
* https://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.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Indicates which collection format should be used while processing the annotated method.
|
||||
*
|
||||
* @author Olga Maciaszek-Sharma
|
||||
* @see feign.CollectionFormat
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface CollectionFormat {
|
||||
|
||||
/**
|
||||
* Allows setting the {@link feign.CollectionFormat} to be used while processing the
|
||||
* annotated method.
|
||||
* @return the {@link feign.CollectionFormat} to be used
|
||||
*/
|
||||
feign.CollectionFormat value();
|
||||
|
||||
}
|
||||
+2
@@ -18,6 +18,7 @@ package org.springframework.cloud.openfeign;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
@@ -36,6 +37,7 @@ import org.springframework.core.annotation.AliasFor;
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
@Inherited
|
||||
public @interface FeignClient {
|
||||
|
||||
/**
|
||||
|
||||
+67
-62
@@ -18,6 +18,7 @@ package org.springframework.cloud.openfeign;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import feign.Client;
|
||||
import feign.Contract;
|
||||
@@ -52,6 +53,7 @@ import org.springframework.util.StringUtils;
|
||||
* @author Eko Kurniawan Khannedy
|
||||
* @author Gregor Zurowski
|
||||
* @author Matt King
|
||||
* @author Olga Maciaszek-Sharma
|
||||
*/
|
||||
public class FeignClientFactoryBean
|
||||
implements FactoryBean<Object>, InitializingBean, ApplicationContextAware {
|
||||
@@ -81,15 +83,19 @@ public class FeignClientFactoryBean
|
||||
|
||||
private Class<?> fallbackFactory = void.class;
|
||||
|
||||
private int readTimeoutMillis = new Request.Options().readTimeoutMillis();
|
||||
|
||||
private int connectTimeoutMillis = new Request.Options().connectTimeoutMillis();
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
Assert.hasText(this.contextId, "Context id must be set");
|
||||
Assert.hasText(this.name, "Name must be set");
|
||||
Assert.hasText(contextId, "Context id must be set");
|
||||
Assert.hasText(name, "Name must be set");
|
||||
}
|
||||
|
||||
protected Feign.Builder feign(FeignContext context) {
|
||||
FeignLoggerFactory loggerFactory = get(context, FeignLoggerFactory.class);
|
||||
Logger logger = loggerFactory.create(this.type);
|
||||
Logger logger = loggerFactory.create(type);
|
||||
|
||||
// @formatter:off
|
||||
Feign.Builder builder = get(context, Feign.Builder.class)
|
||||
@@ -119,7 +125,7 @@ public class FeignClientFactoryBean
|
||||
}
|
||||
|
||||
protected void configureFeign(FeignContext context, Feign.Builder builder) {
|
||||
FeignClientProperties properties = this.applicationContext
|
||||
FeignClientProperties properties = applicationContext
|
||||
.getBean(FeignClientProperties.class);
|
||||
|
||||
FeignClientConfigurer feignClientConfigurer = getOptional(context,
|
||||
@@ -132,15 +138,13 @@ public class FeignClientFactoryBean
|
||||
configureUsingProperties(
|
||||
properties.getConfig().get(properties.getDefaultConfig()),
|
||||
builder);
|
||||
configureUsingProperties(properties.getConfig().get(this.contextId),
|
||||
builder);
|
||||
configureUsingProperties(properties.getConfig().get(contextId), builder);
|
||||
}
|
||||
else {
|
||||
configureUsingProperties(
|
||||
properties.getConfig().get(properties.getDefaultConfig()),
|
||||
builder);
|
||||
configureUsingProperties(properties.getConfig().get(this.contextId),
|
||||
builder);
|
||||
configureUsingProperties(properties.getConfig().get(contextId), builder);
|
||||
configureUsingConfiguration(context, builder);
|
||||
}
|
||||
}
|
||||
@@ -168,7 +172,7 @@ public class FeignClientFactoryBean
|
||||
FeignErrorDecoderFactory errorDecoderFactory = getOptional(context,
|
||||
FeignErrorDecoderFactory.class);
|
||||
if (errorDecoderFactory != null) {
|
||||
ErrorDecoder factoryErrorDecoder = errorDecoderFactory.create(this.type);
|
||||
ErrorDecoder factoryErrorDecoder = errorDecoderFactory.create(type);
|
||||
builder.errorDecoder(factoryErrorDecoder);
|
||||
}
|
||||
}
|
||||
@@ -176,6 +180,8 @@ public class FeignClientFactoryBean
|
||||
Request.Options.class);
|
||||
if (options != null) {
|
||||
builder.options(options);
|
||||
readTimeoutMillis = options.readTimeoutMillis();
|
||||
connectTimeoutMillis = options.connectTimeoutMillis();
|
||||
}
|
||||
Map<String, RequestInterceptor> requestInterceptors = getInheritedAwareInstances(
|
||||
context, RequestInterceptor.class);
|
||||
@@ -187,7 +193,7 @@ public class FeignClientFactoryBean
|
||||
if (queryMapEncoder != null) {
|
||||
builder.queryMapEncoder(queryMapEncoder);
|
||||
}
|
||||
if (this.decode404) {
|
||||
if (decode404) {
|
||||
builder.decode404();
|
||||
}
|
||||
ExceptionPropagationPolicy exceptionPropagationPolicy = getInheritedAwareOptional(
|
||||
@@ -208,10 +214,13 @@ public class FeignClientFactoryBean
|
||||
builder.logLevel(config.getLoggerLevel());
|
||||
}
|
||||
|
||||
if (config.getConnectTimeout() != null && config.getReadTimeout() != null) {
|
||||
builder.options(new Request.Options(config.getConnectTimeout(),
|
||||
config.getReadTimeout()));
|
||||
}
|
||||
connectTimeoutMillis = config.getConnectTimeout() != null
|
||||
? config.getConnectTimeout() : connectTimeoutMillis;
|
||||
readTimeoutMillis = config.getReadTimeout() != null ? config.getReadTimeout()
|
||||
: readTimeoutMillis;
|
||||
|
||||
builder.options(new Request.Options(connectTimeoutMillis, TimeUnit.MILLISECONDS,
|
||||
readTimeoutMillis, TimeUnit.MILLISECONDS, true));
|
||||
|
||||
if (config.getRetryer() != null) {
|
||||
Retryer retryer = getOrInstantiate(config.getRetryer());
|
||||
@@ -257,7 +266,7 @@ public class FeignClientFactoryBean
|
||||
|
||||
private <T> T getOrInstantiate(Class<T> tClass) {
|
||||
try {
|
||||
return this.applicationContext.getBean(tClass);
|
||||
return applicationContext.getBean(tClass);
|
||||
}
|
||||
catch (NoSuchBeanDefinitionException e) {
|
||||
return BeanUtils.instantiateClass(tClass);
|
||||
@@ -265,16 +274,16 @@ public class FeignClientFactoryBean
|
||||
}
|
||||
|
||||
protected <T> T get(FeignContext context, Class<T> type) {
|
||||
T instance = context.getInstance(this.contextId, type);
|
||||
T instance = context.getInstance(contextId, type);
|
||||
if (instance == null) {
|
||||
throw new IllegalStateException(
|
||||
"No bean found of type " + type + " for " + this.contextId);
|
||||
"No bean found of type " + type + " for " + contextId);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
protected <T> T getOptional(FeignContext context, Class<T> type) {
|
||||
return context.getInstance(this.contextId, type);
|
||||
return context.getInstance(contextId, type);
|
||||
}
|
||||
|
||||
protected <T> T getInheritedAwareOptional(FeignContext context, Class<T> type) {
|
||||
@@ -282,17 +291,17 @@ public class FeignClientFactoryBean
|
||||
return getOptional(context, type);
|
||||
}
|
||||
else {
|
||||
return context.getInstanceWithoutAncestors(this.contextId, type);
|
||||
return context.getInstanceWithoutAncestors(contextId, type);
|
||||
}
|
||||
}
|
||||
|
||||
protected <T> Map<String, T> getInheritedAwareInstances(FeignContext context,
|
||||
Class<T> type) {
|
||||
if (inheritParentContext) {
|
||||
return context.getInstances(this.contextId, type);
|
||||
return context.getInstances(contextId, type);
|
||||
}
|
||||
else {
|
||||
return context.getInstancesWithoutAncestors(this.contextId, type);
|
||||
return context.getInstancesWithoutAncestors(contextId, type);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -320,22 +329,22 @@ public class FeignClientFactoryBean
|
||||
* information
|
||||
*/
|
||||
<T> T getTarget() {
|
||||
FeignContext context = this.applicationContext.getBean(FeignContext.class);
|
||||
FeignContext context = applicationContext.getBean(FeignContext.class);
|
||||
Feign.Builder builder = feign(context);
|
||||
|
||||
if (!StringUtils.hasText(this.url)) {
|
||||
if (!this.name.startsWith("http")) {
|
||||
this.url = "http://" + this.name;
|
||||
if (!StringUtils.hasText(url)) {
|
||||
if (!name.startsWith("http")) {
|
||||
url = "http://" + name;
|
||||
}
|
||||
else {
|
||||
this.url = this.name;
|
||||
url = name;
|
||||
}
|
||||
this.url += cleanPath();
|
||||
url += cleanPath();
|
||||
return (T) loadBalance(builder, context,
|
||||
new HardCodedTarget<>(this.type, this.name, this.url));
|
||||
new HardCodedTarget<>(type, name, url));
|
||||
}
|
||||
if (StringUtils.hasText(this.url) && !this.url.startsWith("http")) {
|
||||
this.url = "http://" + this.url;
|
||||
if (StringUtils.hasText(url) && !url.startsWith("http")) {
|
||||
url = "http://" + url;
|
||||
}
|
||||
String url = this.url + cleanPath();
|
||||
Client client = getOptional(context, Client.class);
|
||||
@@ -349,7 +358,7 @@ public class FeignClientFactoryBean
|
||||
}
|
||||
Targeter targeter = get(context, Targeter.class);
|
||||
return (T) targeter.target(this, builder, context,
|
||||
new HardCodedTarget<>(this.type, this.name, url));
|
||||
new HardCodedTarget<>(type, name, url));
|
||||
}
|
||||
|
||||
private String cleanPath() {
|
||||
@@ -367,7 +376,7 @@ public class FeignClientFactoryBean
|
||||
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return this.type;
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -376,7 +385,7 @@ public class FeignClientFactoryBean
|
||||
}
|
||||
|
||||
public Class<?> getType() {
|
||||
return this.type;
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(Class<?> type) {
|
||||
@@ -384,7 +393,7 @@ public class FeignClientFactoryBean
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
@@ -392,7 +401,7 @@ public class FeignClientFactoryBean
|
||||
}
|
||||
|
||||
public String getContextId() {
|
||||
return this.contextId;
|
||||
return contextId;
|
||||
}
|
||||
|
||||
public void setContextId(String contextId) {
|
||||
@@ -400,7 +409,7 @@ public class FeignClientFactoryBean
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return this.url;
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
@@ -408,7 +417,7 @@ public class FeignClientFactoryBean
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return this.path;
|
||||
return path;
|
||||
}
|
||||
|
||||
public void setPath(String path) {
|
||||
@@ -416,7 +425,7 @@ public class FeignClientFactoryBean
|
||||
}
|
||||
|
||||
public boolean isDecode404() {
|
||||
return this.decode404;
|
||||
return decode404;
|
||||
}
|
||||
|
||||
public void setDecode404(boolean decode404) {
|
||||
@@ -432,7 +441,7 @@ public class FeignClientFactoryBean
|
||||
}
|
||||
|
||||
public ApplicationContext getApplicationContext() {
|
||||
return this.applicationContext;
|
||||
return applicationContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -441,7 +450,7 @@ public class FeignClientFactoryBean
|
||||
}
|
||||
|
||||
public Class<?> getFallback() {
|
||||
return this.fallback;
|
||||
return fallback;
|
||||
}
|
||||
|
||||
public void setFallback(Class<?> fallback) {
|
||||
@@ -449,7 +458,7 @@ public class FeignClientFactoryBean
|
||||
}
|
||||
|
||||
public Class<?> getFallbackFactory() {
|
||||
return this.fallbackFactory;
|
||||
return fallbackFactory;
|
||||
}
|
||||
|
||||
public void setFallbackFactory(Class<?> fallbackFactory) {
|
||||
@@ -465,35 +474,31 @@ public class FeignClientFactoryBean
|
||||
return false;
|
||||
}
|
||||
FeignClientFactoryBean that = (FeignClientFactoryBean) o;
|
||||
return Objects.equals(this.applicationContext, that.applicationContext)
|
||||
&& this.decode404 == that.decode404
|
||||
&& this.inheritParentContext == that.inheritParentContext
|
||||
&& Objects.equals(this.fallback, that.fallback)
|
||||
&& Objects.equals(this.fallbackFactory, that.fallbackFactory)
|
||||
&& Objects.equals(this.name, that.name)
|
||||
&& Objects.equals(this.path, that.path)
|
||||
&& Objects.equals(this.type, that.type)
|
||||
&& Objects.equals(this.url, that.url);
|
||||
return Objects.equals(applicationContext, that.applicationContext)
|
||||
&& decode404 == that.decode404
|
||||
&& inheritParentContext == that.inheritParentContext
|
||||
&& Objects.equals(fallback, that.fallback)
|
||||
&& Objects.equals(fallbackFactory, that.fallbackFactory)
|
||||
&& Objects.equals(name, that.name) && Objects.equals(path, that.path)
|
||||
&& Objects.equals(type, that.type) && Objects.equals(url, that.url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(this.applicationContext, this.decode404,
|
||||
this.inheritParentContext, this.fallback, this.fallbackFactory, this.name,
|
||||
this.path, this.type, this.url);
|
||||
return Objects.hash(applicationContext, decode404, inheritParentContext, fallback,
|
||||
fallbackFactory, name, path, type, url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder("FeignClientFactoryBean{").append("type=")
|
||||
.append(this.type).append(", ").append("name='").append(this.name)
|
||||
.append("', ").append("url='").append(this.url).append("', ")
|
||||
.append("path='").append(this.path).append("', ").append("decode404=")
|
||||
.append(this.decode404).append(", ").append("inheritParentContext=")
|
||||
.append(this.inheritParentContext).append(", ")
|
||||
.append("applicationContext=").append(this.applicationContext)
|
||||
.append(", ").append("fallback=").append(this.fallback).append(", ")
|
||||
.append("fallbackFactory=").append(this.fallbackFactory).append("}")
|
||||
return new StringBuilder("FeignClientFactoryBean{").append("type=").append(type)
|
||||
.append(", ").append("name='").append(name).append("', ").append("url='")
|
||||
.append(url).append("', ").append("path='").append(path).append("', ")
|
||||
.append("decode404=").append(decode404).append(", ")
|
||||
.append("inheritParentContext=").append(inheritParentContext).append(", ")
|
||||
.append("applicationContext=").append(applicationContext).append(", ")
|
||||
.append("fallback=").append(fallback).append(", ")
|
||||
.append("fallbackFactory=").append(fallbackFactory).append("}")
|
||||
.toString();
|
||||
}
|
||||
|
||||
|
||||
+1
-5
@@ -16,11 +16,9 @@
|
||||
|
||||
package org.springframework.cloud.openfeign.encoding;
|
||||
|
||||
import feign.Client;
|
||||
import feign.Feign;
|
||||
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
@@ -38,12 +36,10 @@ import org.springframework.context.annotation.Configuration;
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableConfigurationProperties(FeignClientEncodingProperties.class)
|
||||
@ConditionalOnClass(Feign.class)
|
||||
@ConditionalOnBean(Client.class)
|
||||
// The OK HTTP client uses "transparent" compression.
|
||||
// If the content-encoding header is present it disable transparent compression
|
||||
@ConditionalOnMissingBean(type = "okhttp3.OkHttpClient")
|
||||
@ConditionalOnProperty(value = "feign.compression.request.enabled",
|
||||
matchIfMissing = false)
|
||||
@ConditionalOnProperty("feign.compression.request.enabled")
|
||||
@AutoConfigureAfter(FeignAutoConfiguration.class)
|
||||
public class FeignContentGzipEncodingAutoConfiguration {
|
||||
|
||||
|
||||
+22
-16
@@ -37,6 +37,7 @@ import feign.Param;
|
||||
import feign.Request;
|
||||
|
||||
import org.springframework.cloud.openfeign.AnnotatedParameterProcessor;
|
||||
import org.springframework.cloud.openfeign.CollectionFormat;
|
||||
import org.springframework.cloud.openfeign.annotation.MatrixVariableParameterProcessor;
|
||||
import org.springframework.cloud.openfeign.annotation.PathVariableParameterProcessor;
|
||||
import org.springframework.cloud.openfeign.annotation.QueryMapParameterProcessor;
|
||||
@@ -121,9 +122,9 @@ public class SpringMvcContract extends Contract.BaseContract
|
||||
List<AnnotatedParameterProcessor> processors = getDefaultAnnotatedArgumentsProcessors();
|
||||
processors.addAll(annotatedParameterProcessors);
|
||||
|
||||
this.annotatedArgumentProcessors = toAnnotatedArgumentProcessorMap(processors);
|
||||
annotatedArgumentProcessors = toAnnotatedArgumentProcessorMap(processors);
|
||||
this.conversionService = conversionService;
|
||||
this.convertingExpanderFactory = new ConvertingExpanderFactory(conversionService);
|
||||
convertingExpanderFactory = new ConvertingExpanderFactory(conversionService);
|
||||
}
|
||||
|
||||
private static TypeDescriptor createTypeDescriptor(Method method, int paramIndex) {
|
||||
@@ -187,7 +188,7 @@ public class SpringMvcContract extends Contract.BaseContract
|
||||
|
||||
@Override
|
||||
public MethodMetadata parseAndValidateMetadata(Class<?> targetType, Method method) {
|
||||
this.processedMethods.put(Feign.configKey(targetType, method), method);
|
||||
processedMethods.put(Feign.configKey(targetType, method), method);
|
||||
MethodMetadata md = super.parseAndValidateMetadata(targetType, method);
|
||||
|
||||
RequestMapping classAnnotation = findMergedAnnotation(targetType,
|
||||
@@ -213,6 +214,12 @@ public class SpringMvcContract extends Contract.BaseContract
|
||||
@Override
|
||||
protected void processAnnotationOnMethod(MethodMetadata data,
|
||||
Annotation methodAnnotation, Method method) {
|
||||
if (CollectionFormat.class.isInstance(methodAnnotation)) {
|
||||
CollectionFormat collectionFormat = findMergedAnnotation(method,
|
||||
CollectionFormat.class);
|
||||
data.template().collectionFormat(collectionFormat.value());
|
||||
}
|
||||
|
||||
if (!RequestMapping.class.isInstance(methodAnnotation) && !methodAnnotation
|
||||
.annotationType().isAnnotationPresent(RequestMapping.class)) {
|
||||
return;
|
||||
@@ -248,13 +255,13 @@ public class SpringMvcContract extends Contract.BaseContract
|
||||
// headers
|
||||
parseHeaders(data, method, methodMapping);
|
||||
|
||||
data.indexToExpander(new LinkedHashMap<Integer, Param.Expander>());
|
||||
data.indexToExpander(new LinkedHashMap<>());
|
||||
}
|
||||
|
||||
private String resolve(String value) {
|
||||
if (StringUtils.hasText(value)
|
||||
&& this.resourceLoader instanceof ConfigurableApplicationContext) {
|
||||
return ((ConfigurableApplicationContext) this.resourceLoader).getEnvironment()
|
||||
&& resourceLoader instanceof ConfigurableApplicationContext) {
|
||||
return ((ConfigurableApplicationContext) resourceLoader).getEnvironment()
|
||||
.resolvePlaceholders(value);
|
||||
}
|
||||
return value;
|
||||
@@ -280,9 +287,9 @@ public class SpringMvcContract extends Contract.BaseContract
|
||||
|
||||
AnnotatedParameterProcessor.AnnotatedParameterContext context = new SimpleAnnotatedParameterContext(
|
||||
data, paramIndex);
|
||||
Method method = this.processedMethods.get(data.configKey());
|
||||
Method method = processedMethods.get(data.configKey());
|
||||
for (Annotation parameterAnnotation : annotations) {
|
||||
AnnotatedParameterProcessor processor = this.annotatedArgumentProcessors
|
||||
AnnotatedParameterProcessor processor = annotatedArgumentProcessors
|
||||
.get(parameterAnnotation.annotationType());
|
||||
if (processor != null) {
|
||||
Annotation processParameterAnnotation;
|
||||
@@ -298,9 +305,8 @@ public class SpringMvcContract extends Contract.BaseContract
|
||||
if (!isMultipartFormData(data) && isHttpAnnotation
|
||||
&& data.indexToExpander().get(paramIndex) == null) {
|
||||
TypeDescriptor typeDescriptor = createTypeDescriptor(method, paramIndex);
|
||||
if (this.conversionService.canConvert(typeDescriptor,
|
||||
STRING_TYPE_DESCRIPTOR)) {
|
||||
Param.Expander expander = this.convertingExpanderFactory
|
||||
if (conversionService.canConvert(typeDescriptor, STRING_TYPE_DESCRIPTOR)) {
|
||||
Param.Expander expander = convertingExpanderFactory
|
||||
.getExpander(typeDescriptor);
|
||||
if (expander != null) {
|
||||
data.indexToExpander().put(paramIndex, expander);
|
||||
@@ -419,7 +425,7 @@ public class SpringMvcContract extends Contract.BaseContract
|
||||
|
||||
@Override
|
||||
public String expand(Object value) {
|
||||
return this.conversionService.convert(value, String.class);
|
||||
return conversionService.convert(value, String.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -434,7 +440,7 @@ public class SpringMvcContract extends Contract.BaseContract
|
||||
|
||||
Param.Expander getExpander(TypeDescriptor typeDescriptor) {
|
||||
return value -> {
|
||||
Object converted = this.conversionService.convert(value, typeDescriptor,
|
||||
Object converted = conversionService.convert(value, typeDescriptor,
|
||||
STRING_TYPE_DESCRIPTOR);
|
||||
return (String) converted;
|
||||
};
|
||||
@@ -457,17 +463,17 @@ public class SpringMvcContract extends Contract.BaseContract
|
||||
|
||||
@Override
|
||||
public MethodMetadata getMethodMetadata() {
|
||||
return this.methodMetadata;
|
||||
return methodMetadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getParameterIndex() {
|
||||
return this.parameterIndex;
|
||||
return parameterIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParameterName(String name) {
|
||||
nameParam(this.methodMetadata, name, this.parameterIndex);
|
||||
nameParam(methodMetadata, name, parameterIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+3
-1
@@ -29,6 +29,7 @@ import org.junit.Test;
|
||||
|
||||
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
|
||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||
import org.springframework.cloud.client.loadbalancer.reactive.LoadBalancerProperties;
|
||||
import org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient;
|
||||
import org.springframework.cloud.loadbalancer.config.LoadBalancerAutoConfiguration;
|
||||
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
|
||||
@@ -98,7 +99,8 @@ public class FeignClientFactoryTests {
|
||||
|
||||
@Bean
|
||||
BlockingLoadBalancerClient loadBalancerClient() {
|
||||
return new BlockingLoadBalancerClient(new LoadBalancerClientFactory());
|
||||
return new BlockingLoadBalancerClient(new LoadBalancerClientFactory(),
|
||||
new LoadBalancerProperties());
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
+82
-24
@@ -17,13 +17,19 @@
|
||||
package org.springframework.cloud.openfeign;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.lang.reflect.Type;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import feign.InvocationHandlerFactory;
|
||||
import feign.Request;
|
||||
import feign.RequestInterceptor;
|
||||
import feign.RequestTemplate;
|
||||
import feign.RetryableException;
|
||||
@@ -47,6 +53,8 @@ import org.springframework.http.MediaType;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.TestPropertySource;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
@@ -57,7 +65,9 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen
|
||||
|
||||
/**
|
||||
* @author Eko Kurniawan Khannedy
|
||||
* @author Olga Maciaszek-Sharma
|
||||
*/
|
||||
@SuppressWarnings("FieldMayBeFinal")
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringBootTest(classes = FeignClientUsingPropertiesTests.Application.class,
|
||||
webEnvironment = RANDOM_PORT)
|
||||
@@ -83,45 +93,45 @@ public class FeignClientUsingPropertiesTests {
|
||||
private FeignClientFactoryBean formFactoryBean;
|
||||
|
||||
public FeignClientUsingPropertiesTests() {
|
||||
this.fooFactoryBean = new FeignClientFactoryBean();
|
||||
this.fooFactoryBean.setContextId("foo");
|
||||
this.fooFactoryBean.setType(FeignClientFactoryBean.class);
|
||||
fooFactoryBean = new FeignClientFactoryBean();
|
||||
fooFactoryBean.setContextId("foo");
|
||||
fooFactoryBean.setType(FeignClientFactoryBean.class);
|
||||
|
||||
this.barFactoryBean = new FeignClientFactoryBean();
|
||||
this.barFactoryBean.setContextId("bar");
|
||||
this.barFactoryBean.setType(FeignClientFactoryBean.class);
|
||||
barFactoryBean = new FeignClientFactoryBean();
|
||||
barFactoryBean.setContextId("bar");
|
||||
barFactoryBean.setType(FeignClientFactoryBean.class);
|
||||
|
||||
this.unwrapFactoryBean = new FeignClientFactoryBean();
|
||||
this.unwrapFactoryBean.setContextId("unwrap");
|
||||
this.unwrapFactoryBean.setType(FeignClientFactoryBean.class);
|
||||
unwrapFactoryBean = new FeignClientFactoryBean();
|
||||
unwrapFactoryBean.setContextId("unwrap");
|
||||
unwrapFactoryBean.setType(FeignClientFactoryBean.class);
|
||||
|
||||
this.formFactoryBean = new FeignClientFactoryBean();
|
||||
this.formFactoryBean.setContextId("form");
|
||||
this.formFactoryBean.setType(FeignClientFactoryBean.class);
|
||||
formFactoryBean = new FeignClientFactoryBean();
|
||||
formFactoryBean.setContextId("form");
|
||||
formFactoryBean.setType(FeignClientFactoryBean.class);
|
||||
}
|
||||
|
||||
public FooClient fooClient() {
|
||||
this.fooFactoryBean.setApplicationContext(this.applicationContext);
|
||||
return this.fooFactoryBean.feign(this.context).target(FooClient.class,
|
||||
"http://localhost:" + this.port);
|
||||
fooFactoryBean.setApplicationContext(applicationContext);
|
||||
return fooFactoryBean.feign(context).target(FooClient.class,
|
||||
"http://localhost:" + port);
|
||||
}
|
||||
|
||||
public BarClient barClient() {
|
||||
this.barFactoryBean.setApplicationContext(this.applicationContext);
|
||||
return this.barFactoryBean.feign(this.context).target(BarClient.class,
|
||||
"http://localhost:" + this.port);
|
||||
barFactoryBean.setApplicationContext(applicationContext);
|
||||
return barFactoryBean.feign(context).target(BarClient.class,
|
||||
"http://localhost:" + port);
|
||||
}
|
||||
|
||||
public UnwrapClient unwrapClient() {
|
||||
this.unwrapFactoryBean.setApplicationContext(this.applicationContext);
|
||||
return this.unwrapFactoryBean.feign(this.context).target(UnwrapClient.class,
|
||||
"http://localhost:" + this.port);
|
||||
unwrapFactoryBean.setApplicationContext(applicationContext);
|
||||
return unwrapFactoryBean.feign(context).target(UnwrapClient.class,
|
||||
"http://localhost:" + port);
|
||||
}
|
||||
|
||||
public FormClient formClient() {
|
||||
this.formFactoryBean.setApplicationContext(this.applicationContext);
|
||||
return this.formFactoryBean.feign(this.context).target(FormClient.class,
|
||||
"http://localhost:" + this.port);
|
||||
formFactoryBean.setApplicationContext(applicationContext);
|
||||
return formFactoryBean.feign(context).target(FormClient.class,
|
||||
"http://localhost:" + port);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -149,6 +159,47 @@ public class FeignClientUsingPropertiesTests {
|
||||
assertThat(response).isEqualTo("Data");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readTimeoutShouldWorkWhenConnectTimeoutNotSet() {
|
||||
FeignClientFactoryBean readTimeoutFactoryBean = new FeignClientFactoryBean();
|
||||
readTimeoutFactoryBean.setContextId("readTimeout");
|
||||
readTimeoutFactoryBean.setType(FeignClientFactoryBean.class);
|
||||
readTimeoutFactoryBean.setApplicationContext(applicationContext);
|
||||
|
||||
TimeoutClient client = readTimeoutFactoryBean.feign(context)
|
||||
.target(TimeoutClient.class, "http://localhost:" + port);
|
||||
|
||||
Request.Options options = getRequestOptions((Proxy) client);
|
||||
|
||||
assertThat(options.readTimeoutMillis()).isEqualTo(1000);
|
||||
assertThat(options.connectTimeoutMillis()).isEqualTo(5000);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void connectTimeoutShouldWorkWhenReadTimeoutNotSet() {
|
||||
FeignClientFactoryBean readTimeoutFactoryBean = new FeignClientFactoryBean();
|
||||
readTimeoutFactoryBean.setContextId("connectTimeout");
|
||||
readTimeoutFactoryBean.setType(FeignClientFactoryBean.class);
|
||||
readTimeoutFactoryBean.setApplicationContext(applicationContext);
|
||||
|
||||
TimeoutClient client = readTimeoutFactoryBean.feign(context)
|
||||
.target(TimeoutClient.class, "http://localhost:" + port);
|
||||
|
||||
Request.Options options = getRequestOptions((Proxy) client);
|
||||
|
||||
assertThat(options.connectTimeoutMillis()).isEqualTo(1000);
|
||||
assertThat(options.readTimeoutMillis()).isEqualTo(5000);
|
||||
}
|
||||
|
||||
private Request.Options getRequestOptions(Proxy client) {
|
||||
Object invocationHandler = ReflectionTestUtils.getField(client, "h");
|
||||
Map<Method, InvocationHandlerFactory.MethodHandler> dispatch = (Map<Method, InvocationHandlerFactory.MethodHandler>) ReflectionTestUtils
|
||||
.getField(Objects.requireNonNull(invocationHandler), "dispatch");
|
||||
Method key = new ArrayList<>(dispatch.keySet()).get(0);
|
||||
return (Request.Options) ReflectionTestUtils.getField(dispatch.get(key),
|
||||
"options");
|
||||
}
|
||||
|
||||
protected interface FooClient {
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET, value = "/foo")
|
||||
@@ -178,6 +229,13 @@ public class FeignClientUsingPropertiesTests {
|
||||
|
||||
}
|
||||
|
||||
protected interface TimeoutClient {
|
||||
|
||||
@GetMapping("/timeouts")
|
||||
String timeouts();
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableAutoConfiguration
|
||||
@RestController
|
||||
|
||||
+1
-1
@@ -133,7 +133,7 @@ public class SpringDecoderTests extends FeignClientFactoryBean {
|
||||
public void testResponseEntityVoid() {
|
||||
ResponseEntity<Void> response = testClient().getHelloVoid();
|
||||
assertThat(response).as("response was null").isNotNull();
|
||||
List<String> headerVals = response.getHeaders().get("X-test-header");
|
||||
List<String> headerVals = response.getHeaders().get("x-test-header");
|
||||
assertThat(headerVals).as("headerVals was null").isNotNull();
|
||||
assertThat(headerVals.size()).as("headerVals size was wrong").isEqualTo(1);
|
||||
String header = headerVals.get(0);
|
||||
|
||||
+83
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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
|
||||
*
|
||||
* https://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.beans;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
/**
|
||||
* @author Olga Maciaszek-Sharma
|
||||
*/
|
||||
@SpringBootTest(classes = FeignClientMockBeanTests.Config.class)
|
||||
public class FeignClientMockBeanTests {
|
||||
|
||||
@MockBean
|
||||
private RandomClient randomClient;
|
||||
|
||||
@Autowired
|
||||
private TestService testService;
|
||||
|
||||
@Test
|
||||
public void randomClientShouldBeMocked() {
|
||||
String mockMessage = "Mocked Feign Client";
|
||||
when(randomClient.getRandomString()).thenReturn(mockMessage);
|
||||
|
||||
String returnedMessage = testService.testMethod();
|
||||
|
||||
assertThat(returnedMessage).isEqualTo(mockMessage);
|
||||
}
|
||||
|
||||
@FeignClient("random-test")
|
||||
protected interface RandomClient {
|
||||
|
||||
@GetMapping("/random-test")
|
||||
String getRandomString();
|
||||
|
||||
}
|
||||
|
||||
@Configuration
|
||||
protected static class Config {
|
||||
|
||||
@Bean
|
||||
TestService testService() {
|
||||
return new TestService();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class TestService {
|
||||
|
||||
@Autowired
|
||||
private FeignClientMockBeanTests.RandomClient randomClient;
|
||||
|
||||
public String testMethod() {
|
||||
return randomClient.getRandomString();
|
||||
}
|
||||
|
||||
}
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright 2013-2020 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
|
||||
*
|
||||
* https://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.support;
|
||||
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.cloud.openfeign.CollectionFormat;
|
||||
import org.springframework.cloud.openfeign.EnableFeignClients;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.cloud.openfeign.test.NoSecurityConfiguration;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.util.SocketUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Olga Maciaszek-Sharma
|
||||
*/
|
||||
@SpringBootTest(classes = PageableSupportTest.Config.class,
|
||||
webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
|
||||
public class PageableSupportTest {
|
||||
|
||||
@Autowired
|
||||
private PageableFeignClient feignClient;
|
||||
|
||||
@BeforeAll
|
||||
public static void beforeClass() {
|
||||
System.setProperty("server.port",
|
||||
String.valueOf(SocketUtils.findAvailableTcpPort()));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldProperlyFormatPageable() {
|
||||
String direction = feignClient.performRequest(
|
||||
PageRequest.of(1, 10, Sort.by(Sort.Order.desc("property"))));
|
||||
|
||||
assertThat(direction).isEqualTo("DESC");
|
||||
}
|
||||
|
||||
@FeignClient(name = "pageable", url = "http://localhost:${server.port}/")
|
||||
protected interface PageableFeignClient {
|
||||
|
||||
@CollectionFormat(feign.CollectionFormat.CSV)
|
||||
@GetMapping(path = "/page")
|
||||
String performRequest(Pageable page);
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableAutoConfiguration
|
||||
@RestController
|
||||
@EnableFeignClients(clients = PageableFeignClient.class)
|
||||
@Import(NoSecurityConfiguration.class)
|
||||
protected static class Config {
|
||||
|
||||
@GetMapping(path = "/page")
|
||||
String performRequest(Pageable page) {
|
||||
return page.getSort().getOrderFor("property").getDirection().toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+58
-40
@@ -37,6 +37,7 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import org.springframework.cloud.openfeign.CollectionFormat;
|
||||
import org.springframework.cloud.openfeign.SpringQueryMap;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
@@ -62,6 +63,7 @@ import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.ANY;
|
||||
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE;
|
||||
import static feign.CollectionFormat.SSV;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
||||
@@ -71,6 +73,7 @@ import static org.junit.Assume.assumeTrue;
|
||||
* @author Aram Peres
|
||||
* @author Aaron Whiteside
|
||||
* @author Artyom Romanenko
|
||||
* @author Olga Maciaszek-Sharma
|
||||
*/
|
||||
@RunWith(JUnitParamsRunner.class)
|
||||
public class SpringMvcContractTests {
|
||||
@@ -123,14 +126,14 @@ public class SpringMvcContractTests {
|
||||
conversionServiceFactoryBean.afterPropertiesSet();
|
||||
ConversionService conversionService = conversionServiceFactoryBean.getObject();
|
||||
|
||||
this.contract = new SpringMvcContract(Collections.emptyList(), conversionService);
|
||||
contract = new SpringMvcContract(Collections.emptyList(), conversionService);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProcessAnnotationOnMethod_Simple() throws Exception {
|
||||
Method method = TestTemplate_Simple.class.getDeclaredMethod("getTest",
|
||||
String.class);
|
||||
MethodMetadata data = this.contract
|
||||
MethodMetadata data = contract
|
||||
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||
|
||||
assertThat(data.template().url()).isEqualTo("/test/{id}");
|
||||
@@ -143,7 +146,7 @@ public class SpringMvcContractTests {
|
||||
public void testProcessAnnotations_Simple() throws Exception {
|
||||
Method method = TestTemplate_Simple.class.getDeclaredMethod("getTest",
|
||||
String.class);
|
||||
MethodMetadata data = this.contract
|
||||
MethodMetadata data = contract
|
||||
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||
|
||||
assertThat(data.template().url()).isEqualTo("/test/{id}");
|
||||
@@ -158,7 +161,7 @@ public class SpringMvcContractTests {
|
||||
public void testProcessAnnotations_SimpleGetMapping() throws Exception {
|
||||
Method method = TestTemplate_Simple.class.getDeclaredMethod("getMappingTest",
|
||||
String.class);
|
||||
MethodMetadata data = this.contract
|
||||
MethodMetadata data = contract
|
||||
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||
|
||||
assertThat(data.template().url()).isEqualTo("/test/{id}");
|
||||
@@ -174,7 +177,7 @@ public class SpringMvcContractTests {
|
||||
throws Exception {
|
||||
Method method = TestTemplate_Class_Annotations.class
|
||||
.getDeclaredMethod("getSpecificTest", String.class, String.class);
|
||||
MethodMetadata data = this.contract
|
||||
MethodMetadata data = contract
|
||||
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||
|
||||
assertThat(data.template().url()).isEqualTo("/prepend/{classId}/test/{testId}");
|
||||
@@ -188,7 +191,7 @@ public class SpringMvcContractTests {
|
||||
public void testProcessAnnotations_Class_AnnotationsGetAllTests() throws Exception {
|
||||
Method method = TestTemplate_Class_Annotations.class
|
||||
.getDeclaredMethod("getAllTests", String.class);
|
||||
MethodMetadata data = this.contract
|
||||
MethodMetadata data = contract
|
||||
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||
|
||||
assertThat(data.template().url()).isEqualTo("/prepend/{classId}");
|
||||
@@ -201,12 +204,12 @@ public class SpringMvcContractTests {
|
||||
public void testProcessAnnotations_ExtendedInterface() throws Exception {
|
||||
Method extendedMethod = TestTemplate_Extended.class.getMethod("getAllTests",
|
||||
String.class);
|
||||
MethodMetadata extendedData = this.contract.parseAndValidateMetadata(
|
||||
MethodMetadata extendedData = contract.parseAndValidateMetadata(
|
||||
extendedMethod.getDeclaringClass(), extendedMethod);
|
||||
|
||||
Method method = TestTemplate_Class_Annotations.class
|
||||
.getDeclaredMethod("getAllTests", String.class);
|
||||
MethodMetadata data = this.contract
|
||||
MethodMetadata data = contract
|
||||
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||
|
||||
assertThat(data.template().url()).isEqualTo(extendedData.template().url());
|
||||
@@ -220,7 +223,7 @@ public class SpringMvcContractTests {
|
||||
public void testProcessAnnotations_SimplePost() throws Exception {
|
||||
Method method = TestTemplate_Simple.class.getDeclaredMethod("postTest",
|
||||
TestObject.class);
|
||||
MethodMetadata data = this.contract
|
||||
MethodMetadata data = contract
|
||||
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||
|
||||
assertThat(data.template().url()).isEqualTo("/");
|
||||
@@ -234,7 +237,7 @@ public class SpringMvcContractTests {
|
||||
public void testProcessAnnotations_SimplePostMapping() throws Exception {
|
||||
Method method = TestTemplate_Simple.class.getDeclaredMethod("postMappingTest",
|
||||
TestObject.class);
|
||||
MethodMetadata data = this.contract
|
||||
MethodMetadata data = contract
|
||||
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||
|
||||
assertThat(data.template().url()).isEqualTo("/");
|
||||
@@ -248,7 +251,7 @@ public class SpringMvcContractTests {
|
||||
public void testProcessAnnotationsOnMethod_Advanced() throws Exception {
|
||||
Method method = TestTemplate_Advanced.class.getDeclaredMethod("getTest",
|
||||
String.class, String.class, Integer.class);
|
||||
MethodMetadata data = this.contract
|
||||
MethodMetadata data = contract
|
||||
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||
|
||||
assertThat(data.template().url())
|
||||
@@ -263,16 +266,28 @@ public class SpringMvcContractTests {
|
||||
throws Exception {
|
||||
Method method = TestTemplate_Advanced.class.getDeclaredMethod("getTest",
|
||||
String.class, String.class, Integer.class);
|
||||
this.contract.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||
contract.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||
|
||||
// Don't throw an exception and this passes
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProcessAnnotationsOnMethod_CollectionFormat()
|
||||
throws NoSuchMethodException {
|
||||
Method method = TestTemplate_Advanced.class
|
||||
.getDeclaredMethod("getWithCollectionFormat");
|
||||
|
||||
MethodMetadata data = contract
|
||||
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||
|
||||
assertThat(data.template().collectionFormat()).isEqualTo(SSV);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProcessAnnotations_Advanced() throws Exception {
|
||||
Method method = TestTemplate_Advanced.class.getDeclaredMethod("getTest",
|
||||
String.class, String.class, Integer.class);
|
||||
MethodMetadata data = this.contract
|
||||
MethodMetadata data = contract
|
||||
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||
|
||||
assertThat(data.template().url())
|
||||
@@ -297,7 +312,7 @@ public class SpringMvcContractTests {
|
||||
public void testProcessAnnotations_Aliased() throws Exception {
|
||||
Method method = TestTemplate_Advanced.class.getDeclaredMethod("getTest2",
|
||||
String.class, Integer.class);
|
||||
MethodMetadata data = this.contract
|
||||
MethodMetadata data = contract
|
||||
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||
|
||||
assertThat(data.template().url())
|
||||
@@ -320,7 +335,7 @@ public class SpringMvcContractTests {
|
||||
public void testProcessAnnotations_DateTimeFormatParam() throws Exception {
|
||||
Method method = TestTemplate_DateTimeFormatParameter.class
|
||||
.getDeclaredMethod("getTest", LocalDateTime.class);
|
||||
MethodMetadata data = this.contract
|
||||
MethodMetadata data = contract
|
||||
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||
|
||||
Param.Expander expander = data.indexToExpander().get(0);
|
||||
@@ -340,7 +355,7 @@ public class SpringMvcContractTests {
|
||||
public void testProcessAnnotations_NumberFormatParam() throws Exception {
|
||||
Method method = TestTemplate_NumberFormatParameter.class
|
||||
.getDeclaredMethod("getTest", BigDecimal.class);
|
||||
MethodMetadata data = this.contract
|
||||
MethodMetadata data = contract
|
||||
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||
|
||||
Param.Expander expander = data.indexToExpander().get(0);
|
||||
@@ -360,7 +375,7 @@ public class SpringMvcContractTests {
|
||||
@Test
|
||||
public void testProcessAnnotations_Advanced2() throws Exception {
|
||||
Method method = TestTemplate_Advanced.class.getDeclaredMethod("getTest");
|
||||
MethodMetadata data = this.contract
|
||||
MethodMetadata data = contract
|
||||
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||
|
||||
assertThat(data.template().url()).isEqualTo("/advanced");
|
||||
@@ -372,7 +387,7 @@ public class SpringMvcContractTests {
|
||||
@Test
|
||||
public void testProcessAnnotations_Advanced3() throws Exception {
|
||||
Method method = TestTemplate_Simple.class.getDeclaredMethod("getTest");
|
||||
MethodMetadata data = this.contract
|
||||
MethodMetadata data = contract
|
||||
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||
|
||||
assertThat(data.template().url()).isEqualTo("/");
|
||||
@@ -385,7 +400,7 @@ public class SpringMvcContractTests {
|
||||
public void testProcessAnnotations_ListParams() throws Exception {
|
||||
Method method = TestTemplate_ListParams.class.getDeclaredMethod("getTest",
|
||||
List.class);
|
||||
MethodMetadata data = this.contract
|
||||
MethodMetadata data = contract
|
||||
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||
|
||||
assertThat(data.template().url()).isEqualTo("/test?id=" + "{id}");
|
||||
@@ -398,7 +413,7 @@ public class SpringMvcContractTests {
|
||||
public void testProcessAnnotations_ListParamsWithoutName() throws Exception {
|
||||
Method method = TestTemplate_ListParamsWithoutName.class
|
||||
.getDeclaredMethod("getTest", List.class);
|
||||
MethodMetadata data = this.contract
|
||||
MethodMetadata data = contract
|
||||
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||
|
||||
assertThat(data.template().url()).isEqualTo("/test?id=" + "{id}");
|
||||
@@ -411,7 +426,7 @@ public class SpringMvcContractTests {
|
||||
public void testProcessAnnotations_MapParams() throws Exception {
|
||||
Method method = TestTemplate_MapParams.class.getDeclaredMethod("getTest",
|
||||
Map.class);
|
||||
MethodMetadata data = this.contract
|
||||
MethodMetadata data = contract
|
||||
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||
|
||||
assertThat(data.template().url()).isEqualTo("/test");
|
||||
@@ -424,12 +439,12 @@ public class SpringMvcContractTests {
|
||||
public void testProcessHeaders() throws Exception {
|
||||
Method method = TestTemplate_Headers.class.getDeclaredMethod("getTest",
|
||||
String.class);
|
||||
MethodMetadata data = this.contract
|
||||
MethodMetadata data = contract
|
||||
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||
|
||||
assertThat(data.template().url()).isEqualTo("/test/{id}");
|
||||
assertThat(data.template().method()).isEqualTo("GET");
|
||||
assertThat(data.template().headers().get("X-Foo").iterator().next())
|
||||
assertThat(data.template().headers().get("x-Foo").iterator().next())
|
||||
.isEqualTo("bar");
|
||||
}
|
||||
|
||||
@@ -437,7 +452,7 @@ public class SpringMvcContractTests {
|
||||
public void testProcessHeadersWithoutValues() throws Exception {
|
||||
Method method = TestTemplate_HeadersWithoutValues.class
|
||||
.getDeclaredMethod("getTest", String.class);
|
||||
MethodMetadata data = this.contract
|
||||
MethodMetadata data = contract
|
||||
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||
|
||||
assertThat(data.template().url()).isEqualTo("/test/{id}");
|
||||
@@ -453,7 +468,7 @@ public class SpringMvcContractTests {
|
||||
assumeTrue("does not have java 8 parameter names",
|
||||
hasJava8ParameterNames(method));
|
||||
|
||||
MethodMetadata data = this.contract
|
||||
MethodMetadata data = contract
|
||||
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||
|
||||
assertThat(data.template().url())
|
||||
@@ -477,7 +492,7 @@ public class SpringMvcContractTests {
|
||||
public void testProcessHeaderMap() throws Exception {
|
||||
Method method = TestTemplate_HeaderMap.class.getDeclaredMethod("headerMap",
|
||||
MultiValueMap.class, String.class);
|
||||
MethodMetadata data = this.contract
|
||||
MethodMetadata data = contract
|
||||
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||
|
||||
assertThat(data.template().url()).isEqualTo("/headerMap");
|
||||
@@ -491,14 +506,14 @@ public class SpringMvcContractTests {
|
||||
public void testProcessHeaderMapMoreThanOnce() throws Exception {
|
||||
Method method = TestTemplate_HeaderMap.class.getDeclaredMethod(
|
||||
"headerMapMoreThanOnce", MultiValueMap.class, MultiValueMap.class);
|
||||
this.contract.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||
contract.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testProcessQueryMap() throws Exception {
|
||||
Method method = TestTemplate_QueryMap.class.getDeclaredMethod("queryMap",
|
||||
MultiValueMap.class, String.class);
|
||||
MethodMetadata data = this.contract
|
||||
MethodMetadata data = contract
|
||||
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||
|
||||
assertThat(data.template().url()).isEqualTo("/queryMap?aParam=" + "{aParam}");
|
||||
@@ -512,7 +527,7 @@ public class SpringMvcContractTests {
|
||||
public void testProcessQueryMapObject() throws Exception {
|
||||
Method method = TestTemplate_QueryMap.class.getDeclaredMethod("queryMapObject",
|
||||
TestObject.class, String.class);
|
||||
MethodMetadata data = this.contract
|
||||
MethodMetadata data = contract
|
||||
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||
|
||||
assertThat(data.template().url())
|
||||
@@ -527,14 +542,14 @@ public class SpringMvcContractTests {
|
||||
public void testProcessQueryMapMoreThanOnce() throws Exception {
|
||||
Method method = TestTemplate_QueryMap.class.getDeclaredMethod(
|
||||
"queryMapMoreThanOnce", MultiValueMap.class, MultiValueMap.class);
|
||||
this.contract.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||
contract.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMatrixVariable_MapParam() throws Exception {
|
||||
Method method = TestTemplate_MatrixVariable.class
|
||||
.getDeclaredMethod("matrixVariable", Map.class);
|
||||
MethodMetadata data = this.contract
|
||||
MethodMetadata data = contract
|
||||
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||
|
||||
Map<String, String> testMap = new HashMap<>();
|
||||
@@ -550,7 +565,7 @@ public class SpringMvcContractTests {
|
||||
public void testMatrixVariable_ObjectParam() throws Exception {
|
||||
Method method = TestTemplate_MatrixVariable.class
|
||||
.getDeclaredMethod("matrixVariableObject", Object.class);
|
||||
MethodMetadata data = this.contract
|
||||
MethodMetadata data = contract
|
||||
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||
|
||||
assertThat(data.template().method()).isEqualTo("GET");
|
||||
@@ -563,7 +578,7 @@ public class SpringMvcContractTests {
|
||||
public void testMatrixVariableWithNoName() throws NoSuchMethodException {
|
||||
Method method = TestTemplate_MatrixVariable.class
|
||||
.getDeclaredMethod("matrixVariableNotNamed", Map.class);
|
||||
MethodMetadata data = this.contract
|
||||
MethodMetadata data = contract
|
||||
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||
Map<String, String> testMap = new HashMap<>();
|
||||
|
||||
@@ -774,6 +789,10 @@ public class SpringMvcContractTests {
|
||||
@RequestMapping("/advanced")
|
||||
public interface TestTemplate_Advanced {
|
||||
|
||||
@CollectionFormat(SSV)
|
||||
@GetMapping
|
||||
ResponseEntity<TestObject> getWithCollectionFormat();
|
||||
|
||||
@ExceptionHandler
|
||||
@RequestMapping(path = "/test/{id}", method = RequestMethod.PUT,
|
||||
produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
@@ -883,11 +902,10 @@ public class SpringMvcContractTests {
|
||||
|
||||
TestObject that = (TestObject) o;
|
||||
|
||||
if (this.number != null ? !this.number.equals(that.number)
|
||||
: that.number != null) {
|
||||
if (number != null ? !number.equals(that.number) : that.number != null) {
|
||||
return false;
|
||||
}
|
||||
if (this.something != null ? !this.something.equals(that.something)
|
||||
if (something != null ? !something.equals(that.something)
|
||||
: that.something != null) {
|
||||
return false;
|
||||
}
|
||||
@@ -897,16 +915,16 @@ public class SpringMvcContractTests {
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = (this.something != null ? this.something.hashCode() : 0);
|
||||
result = 31 * result + (this.number != null ? this.number.hashCode() : 0);
|
||||
int result = (something != null ? something.hashCode() : 0);
|
||||
result = 31 * result + (number != null ? number.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return new StringBuilder("TestObject{").append("something='")
|
||||
.append(this.something).append("', ").append("number=")
|
||||
.append(this.number).append("}").toString();
|
||||
.append(something).append("', ").append("number=").append(number)
|
||||
.append("}").toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -86,7 +86,7 @@ public class FeignHttpClientTests {
|
||||
public void testPatch() {
|
||||
ResponseEntity<Void> response = this.testClient.patchHello(new Hello("foo"));
|
||||
assertThat(response).isNotNull();
|
||||
String header = response.getHeaders().getFirst("X-Hello");
|
||||
String header = response.getHeaders().getFirst("x-hello");
|
||||
assertThat(header).isEqualTo("hello world patch");
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -88,7 +88,7 @@ public class FeignOkHttpTests {
|
||||
public void testPatch() {
|
||||
ResponseEntity<Void> response = this.testClient.patchHello(new Hello("foo"));
|
||||
assertThat(response).isNotNull();
|
||||
String header = response.getHeaders().getFirst("X-Hello");
|
||||
String header = response.getHeaders().getFirst("x-hello");
|
||||
assertThat(header).isEqualTo("hello world patch");
|
||||
}
|
||||
|
||||
|
||||
@@ -16,3 +16,5 @@ feign.client.config.form.encoder=org.springframework.cloud.openfeign.FeignClient
|
||||
feign.client.config.unwrap.connectTimeout=1000
|
||||
feign.client.config.unwrap.readTimeout=1000
|
||||
feign.client.config.unwrap.exceptionPropagationPolicy=unwrap
|
||||
feign.client.config.readTimeout.readTimeout=1000
|
||||
feign.client.config.connectTimeout.connectTimeout=1000
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
<parent>
|
||||
<artifactId>spring-cloud-dependencies-parent</artifactId>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<version>3.0.0-M2</version>
|
||||
<version>3.0.0-M3</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
<artifactId>spring-cloud-openfeign-dependencies</artifactId>
|
||||
<version>3.0.0-M2</version>
|
||||
<version>3.0.0-M3</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>spring-cloud-openfeign-dependencies</name>
|
||||
<description>Spring Cloud OpenFeign Dependencies</description>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-openfeign</artifactId>
|
||||
<version>3.0.0-M2</version>
|
||||
<version>3.0.0-M3</version>
|
||||
<relativePath>..</relativePath>
|
||||
</parent>
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
|
||||
Reference in New Issue
Block a user