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 | ||
|
|
6d3181e718 | ||
|
|
3002643ee7 | ||
|
|
b1ec55cb01 | ||
|
|
f0e0e7ea64 | ||
|
|
d0278f63b1 | ||
|
|
39e915e568 | ||
|
|
7311e4abc8 | ||
|
|
ad776a43b5 | ||
|
|
e03d7da36d | ||
|
|
dcd5a56c86 | ||
|
|
d492fe0742 | ||
|
|
c9fe3af3ef | ||
|
|
afb0b436c0 | ||
|
|
c85853ac9d | ||
|
|
21986f5e92 | ||
|
|
f857cca5b3 | ||
|
|
1929dae2d2 | ||
|
|
94ad7066a6 | ||
|
|
fc9b47c3b3 | ||
|
|
e7932a6aae | ||
|
|
1b66594ed4 | ||
|
|
25a988e1bf | ||
|
|
af103e0137 | ||
|
|
06a55b8bcd | ||
|
|
090c85c7ed | ||
|
|
88633c7f54 | ||
|
|
bb499ea823 | ||
|
|
0e1a579de5 | ||
|
|
b538d7f88c | ||
|
|
525bb603f7 | ||
|
|
ea3fb86690 | ||
|
|
9a335536bc | ||
|
|
f6cf14f257 | ||
|
|
6ac428b21c | ||
|
|
30eafcd02d | ||
|
|
147136b85b | ||
|
|
45589b7977 | ||
|
|
f4b49d5542 | ||
|
|
a6b5663c69 | ||
|
|
59ba6b1bc6 | ||
|
|
8f421ced21 | ||
|
|
dd91dcdf8d | ||
|
|
78653c3e8e |
+7
-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"]
|
||||
@@ -99,6 +100,11 @@ https://eclipse.org[Eclipse] when working with the code. We use the
|
||||
https://eclipse.org/m2e/[m2eclipse] eclipse plugin for maven support. Other IDEs and tools
|
||||
should also work without issue as long as they use Maven 3.3.3 or better.
|
||||
|
||||
==== Activate the Spring Maven profile
|
||||
Spring Cloud projects require the 'spring' Maven profile to be activated to resolve
|
||||
the spring milestone and snapshot repositories. Use your preferred IDE to set this
|
||||
profile to be active, or you may experience build errors.
|
||||
|
||||
==== Importing into eclipse with m2eclipse
|
||||
We recommend the https://eclipse.org/m2e/[m2eclipse] eclipse plugin when working with
|
||||
eclipse. If you don't already have m2eclipse installed it is available from the "eclipse
|
||||
@@ -307,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.
|
||||
|
||||
+5
-13
@@ -6,17 +6,17 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-openfeign</artifactId>
|
||||
<version>3.0.0.M1</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>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
@@ -25,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>
|
||||
@@ -64,8 +57,7 @@
|
||||
<artifactId>maven-antrun-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<artifactId>maven-deploy-plugin</artifactId>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
@@ -21,4 +21,4 @@
|
||||
|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.
|
||||
|
||||
|===
|
||||
|===
|
||||
@@ -47,6 +47,9 @@ public interface StoreClient {
|
||||
@RequestMapping(method = RequestMethod.GET, value = "/stores")
|
||||
List<Store> getStores();
|
||||
|
||||
@RequestMapping(method = RequestMethod.GET, value = "/stores")
|
||||
Page<Store> getStores(Pageable pageable);
|
||||
|
||||
@RequestMapping(method = RequestMethod.POST, value = "/stores/{storeId}", consumes = "application/json")
|
||||
Store update(@PathVariable("storeId") Long storeId, Store store);
|
||||
}
|
||||
@@ -115,10 +118,12 @@ 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.
|
||||
|
||||
Spring Cloud Netflix _does not_ provide the following beans by default for feign, but still looks up beans of these types from the application context to create the feign client:
|
||||
Spring Cloud OpenFeign _does not_ provide the following beans by default for feign, but still looks up beans of these types from the application context to create the feign client:
|
||||
|
||||
* `Logger.Level`
|
||||
* `Retryer`
|
||||
@@ -128,6 +133,10 @@ Spring Cloud Netflix _does not_ provide the following beans by default for feign
|
||||
* `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]
|
||||
@@ -232,6 +241,29 @@ public interface BarClient {
|
||||
}
|
||||
----
|
||||
|
||||
It is also possible to configure FeignClient not to inherit beans from the parent context.
|
||||
You can do this by overriding the `inheritParentConfiguration()` in a `FeignClientConfigurer`
|
||||
bean to return `false`:
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@Configuration
|
||||
public class CustomConfiguration{
|
||||
|
||||
@Bean
|
||||
public FeignClientConfigurer feignClientConfigurer() {
|
||||
return new FeignClientConfigurer() {
|
||||
|
||||
@Override
|
||||
public boolean inheritParentConfiguration() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
=== Creating Feign Clients Manually
|
||||
|
||||
In some cases it might be necessary to customize your Feign Clients in a way that is not
|
||||
@@ -277,6 +309,9 @@ NOTE: The Feign `Contract` object defines what annotations and values are valid
|
||||
autowired `Contract` bean provides supports for SpringMVC annotations, instead of
|
||||
the default Feign native annotations.
|
||||
|
||||
You can also use the `Builder`to configure FeignClient not to inherit beans from the parent context.
|
||||
You can do this by overriding calling `inheritParentContext(false)` on the `Builder`.
|
||||
|
||||
[[spring-cloud-feign-hystrix]]
|
||||
=== Feign Hystrix Support
|
||||
|
||||
@@ -547,8 +582,29 @@ 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.
|
||||
|
||||
=== Troubleshooting
|
||||
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.
|
||||
|
||||
Until that is done, we recommend using https://github.com/Playtika/feign-reactive[feign-reactive] for Spring WebClient support.
|
||||
|
||||
==== Early Initialization Errors
|
||||
|
||||
|
||||
@@ -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.M1</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.M1</version>
|
||||
<version>3.0.0-M3</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
<scm>
|
||||
@@ -26,8 +26,7 @@
|
||||
<properties>
|
||||
<main.basedir>${basedir}</main.basedir>
|
||||
<jackson.version>2.7.3</jackson.version>
|
||||
<spring-cloud-commons.version>3.0.0.M1</spring-cloud-commons.version>
|
||||
<spring-cloud-netflix.version>3.0.0.M1</spring-cloud-netflix.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>
|
||||
@@ -96,13 +95,6 @@
|
||||
|
||||
<dependencyManagement>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix-dependencies</artifactId>
|
||||
<version>${spring-cloud-netflix.version}</version>
|
||||
<type>pom</type>
|
||||
<scope>import</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-commons-dependencies</artifactId>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-openfeign</artifactId>
|
||||
<version>3.0.0.M1</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>
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+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();
|
||||
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016-2019 the original author or authors.
|
||||
* Copyright 2016-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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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 feign.Feign;
|
||||
|
||||
/**
|
||||
* Allows application to customize the Feign builder.
|
||||
*
|
||||
* @author Matt King
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface FeignBuilderCustomizer {
|
||||
|
||||
void customize(Feign.Builder builder);
|
||||
|
||||
}
|
||||
+3
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
@@ -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 {
|
||||
|
||||
/**
|
||||
|
||||
+20
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
@@ -25,6 +25,7 @@ import org.springframework.context.ApplicationContext;
|
||||
* {@link FeignClient} annotation.
|
||||
*
|
||||
* @author Sven Döring
|
||||
* @author Matt King
|
||||
*/
|
||||
public class FeignClientBuilder {
|
||||
|
||||
@@ -38,6 +39,11 @@ public class FeignClientBuilder {
|
||||
return new Builder<>(this.applicationContext, type, name);
|
||||
}
|
||||
|
||||
public <T> Builder<T> forType(final Class<T> type,
|
||||
final FeignClientFactoryBean clientFactoryBean, final String name) {
|
||||
return new Builder<>(this.applicationContext, clientFactoryBean, type, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder of feign targets.
|
||||
*
|
||||
@@ -49,12 +55,19 @@ public class FeignClientBuilder {
|
||||
|
||||
private Builder(final ApplicationContext applicationContext, final Class<T> type,
|
||||
final String name) {
|
||||
this.feignClientFactoryBean = new FeignClientFactoryBean();
|
||||
this(applicationContext, new FeignClientFactoryBean(), type, name);
|
||||
}
|
||||
|
||||
private Builder(final ApplicationContext applicationContext,
|
||||
final FeignClientFactoryBean clientFactoryBean, final Class<T> type,
|
||||
final String name) {
|
||||
this.feignClientFactoryBean = clientFactoryBean;
|
||||
|
||||
this.feignClientFactoryBean.setApplicationContext(applicationContext);
|
||||
this.feignClientFactoryBean.setType(type);
|
||||
this.feignClientFactoryBean.setName(FeignClientsRegistrar.getName(name));
|
||||
this.feignClientFactoryBean.setContextId(FeignClientsRegistrar.getName(name));
|
||||
this.feignClientFactoryBean.setInheritParentContext(true);
|
||||
// preset default values - these values resemble the default values on the
|
||||
// FeignClient annotation
|
||||
this.url("").path("").decode404(false);
|
||||
@@ -80,6 +93,11 @@ public class FeignClientBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder<T> inheritParentContext(final boolean inheritParentContext) {
|
||||
this.feignClientFactoryBean.setInheritParentContext(inheritParentContext);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder<T> fallback(final Class<? extends T> fallback) {
|
||||
FeignClientsRegistrar.validateFallback(fallback);
|
||||
this.feignClientFactoryBean.setFallback(fallback);
|
||||
|
||||
+130
-68
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
@@ -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;
|
||||
@@ -38,9 +39,11 @@ import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
|
||||
import org.springframework.cloud.openfeign.clientconfig.FeignClientConfigurer;
|
||||
import org.springframework.cloud.openfeign.loadbalancer.FeignBlockingLoadBalancerClient;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -49,8 +52,10 @@ import org.springframework.util.StringUtils;
|
||||
* @author Venil Noronha
|
||||
* @author Eko Kurniawan Khannedy
|
||||
* @author Gregor Zurowski
|
||||
* @author Matt King
|
||||
* @author Olga Maciaszek-Sharma
|
||||
*/
|
||||
class FeignClientFactoryBean
|
||||
public class FeignClientFactoryBean
|
||||
implements FactoryBean<Object>, InitializingBean, ApplicationContextAware {
|
||||
|
||||
/***********************************
|
||||
@@ -70,21 +75,27 @@ class FeignClientFactoryBean
|
||||
|
||||
private boolean decode404;
|
||||
|
||||
private boolean inheritParentContext = true;
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
private Class<?> fallback = void.class;
|
||||
|
||||
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)
|
||||
@@ -96,28 +107,44 @@ class FeignClientFactoryBean
|
||||
// @formatter:on
|
||||
|
||||
configureFeign(context, builder);
|
||||
applyBuildCustomizers(context, builder);
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
private void applyBuildCustomizers(FeignContext context, Feign.Builder builder) {
|
||||
Map<String, FeignBuilderCustomizer> customizerMap = context
|
||||
.getInstances(contextId, FeignBuilderCustomizer.class);
|
||||
|
||||
if (customizerMap != null) {
|
||||
customizerMap.values().stream()
|
||||
.sorted(AnnotationAwareOrderComparator.INSTANCE)
|
||||
.forEach(feignBuilderCustomizer -> feignBuilderCustomizer
|
||||
.customize(builder));
|
||||
}
|
||||
}
|
||||
|
||||
protected void configureFeign(FeignContext context, Feign.Builder builder) {
|
||||
FeignClientProperties properties = this.applicationContext
|
||||
FeignClientProperties properties = applicationContext
|
||||
.getBean(FeignClientProperties.class);
|
||||
if (properties != null) {
|
||||
|
||||
FeignClientConfigurer feignClientConfigurer = getOptional(context,
|
||||
FeignClientConfigurer.class);
|
||||
setInheritParentContext(feignClientConfigurer.inheritParentConfiguration());
|
||||
|
||||
if (properties != null && inheritParentContext) {
|
||||
if (properties.isDefaultToProperties()) {
|
||||
configureUsingConfiguration(context, builder);
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -128,15 +155,16 @@ class FeignClientFactoryBean
|
||||
|
||||
protected void configureUsingConfiguration(FeignContext context,
|
||||
Feign.Builder builder) {
|
||||
Logger.Level level = getOptional(context, Logger.Level.class);
|
||||
Logger.Level level = getInheritedAwareOptional(context, Logger.Level.class);
|
||||
if (level != null) {
|
||||
builder.logLevel(level);
|
||||
}
|
||||
Retryer retryer = getOptional(context, Retryer.class);
|
||||
Retryer retryer = getInheritedAwareOptional(context, Retryer.class);
|
||||
if (retryer != null) {
|
||||
builder.retryer(retryer);
|
||||
}
|
||||
ErrorDecoder errorDecoder = getOptional(context, ErrorDecoder.class);
|
||||
ErrorDecoder errorDecoder = getInheritedAwareOptional(context,
|
||||
ErrorDecoder.class);
|
||||
if (errorDecoder != null) {
|
||||
builder.errorDecoder(errorDecoder);
|
||||
}
|
||||
@@ -144,28 +172,32 @@ 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);
|
||||
}
|
||||
}
|
||||
Request.Options options = getOptional(context, Request.Options.class);
|
||||
Request.Options options = getInheritedAwareOptional(context,
|
||||
Request.Options.class);
|
||||
if (options != null) {
|
||||
builder.options(options);
|
||||
readTimeoutMillis = options.readTimeoutMillis();
|
||||
connectTimeoutMillis = options.connectTimeoutMillis();
|
||||
}
|
||||
Map<String, RequestInterceptor> requestInterceptors = context
|
||||
.getInstances(this.contextId, RequestInterceptor.class);
|
||||
Map<String, RequestInterceptor> requestInterceptors = getInheritedAwareInstances(
|
||||
context, RequestInterceptor.class);
|
||||
if (requestInterceptors != null) {
|
||||
builder.requestInterceptors(requestInterceptors.values());
|
||||
}
|
||||
QueryMapEncoder queryMapEncoder = getOptional(context, QueryMapEncoder.class);
|
||||
QueryMapEncoder queryMapEncoder = getInheritedAwareOptional(context,
|
||||
QueryMapEncoder.class);
|
||||
if (queryMapEncoder != null) {
|
||||
builder.queryMapEncoder(queryMapEncoder);
|
||||
}
|
||||
if (this.decode404) {
|
||||
if (decode404) {
|
||||
builder.decode404();
|
||||
}
|
||||
ExceptionPropagationPolicy exceptionPropagationPolicy = getOptional(context,
|
||||
ExceptionPropagationPolicy.class);
|
||||
ExceptionPropagationPolicy exceptionPropagationPolicy = getInheritedAwareOptional(
|
||||
context, ExceptionPropagationPolicy.class);
|
||||
if (exceptionPropagationPolicy != null) {
|
||||
builder.exceptionPropagationPolicy(exceptionPropagationPolicy);
|
||||
}
|
||||
@@ -182,10 +214,13 @@ 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());
|
||||
@@ -231,7 +266,7 @@ 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);
|
||||
@@ -239,16 +274,35 @@ 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) {
|
||||
if (inheritParentContext) {
|
||||
return getOptional(context, type);
|
||||
}
|
||||
else {
|
||||
return context.getInstanceWithoutAncestors(contextId, type);
|
||||
}
|
||||
}
|
||||
|
||||
protected <T> Map<String, T> getInheritedAwareInstances(FeignContext context,
|
||||
Class<T> type) {
|
||||
if (inheritParentContext) {
|
||||
return context.getInstances(contextId, type);
|
||||
}
|
||||
else {
|
||||
return context.getInstancesWithoutAncestors(contextId, type);
|
||||
}
|
||||
}
|
||||
|
||||
protected <T> T loadBalance(Feign.Builder builder, FeignContext context,
|
||||
@@ -275,22 +329,22 @@ 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);
|
||||
@@ -304,7 +358,7 @@ 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() {
|
||||
@@ -322,7 +376,7 @@ class FeignClientFactoryBean
|
||||
|
||||
@Override
|
||||
public Class<?> getObjectType() {
|
||||
return this.type;
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -331,7 +385,7 @@ class FeignClientFactoryBean
|
||||
}
|
||||
|
||||
public Class<?> getType() {
|
||||
return this.type;
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(Class<?> type) {
|
||||
@@ -339,7 +393,7 @@ class FeignClientFactoryBean
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
@@ -347,7 +401,7 @@ class FeignClientFactoryBean
|
||||
}
|
||||
|
||||
public String getContextId() {
|
||||
return this.contextId;
|
||||
return contextId;
|
||||
}
|
||||
|
||||
public void setContextId(String contextId) {
|
||||
@@ -355,7 +409,7 @@ class FeignClientFactoryBean
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return this.url;
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
@@ -363,7 +417,7 @@ class FeignClientFactoryBean
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return this.path;
|
||||
return path;
|
||||
}
|
||||
|
||||
public void setPath(String path) {
|
||||
@@ -371,15 +425,23 @@ class FeignClientFactoryBean
|
||||
}
|
||||
|
||||
public boolean isDecode404() {
|
||||
return this.decode404;
|
||||
return decode404;
|
||||
}
|
||||
|
||||
public void setDecode404(boolean decode404) {
|
||||
this.decode404 = decode404;
|
||||
}
|
||||
|
||||
public boolean isInheritParentContext() {
|
||||
return inheritParentContext;
|
||||
}
|
||||
|
||||
public void setInheritParentContext(boolean inheritParentContext) {
|
||||
this.inheritParentContext = inheritParentContext;
|
||||
}
|
||||
|
||||
public ApplicationContext getApplicationContext() {
|
||||
return this.applicationContext;
|
||||
return applicationContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -388,7 +450,7 @@ class FeignClientFactoryBean
|
||||
}
|
||||
|
||||
public Class<?> getFallback() {
|
||||
return this.fallback;
|
||||
return fallback;
|
||||
}
|
||||
|
||||
public void setFallback(Class<?> fallback) {
|
||||
@@ -396,7 +458,7 @@ class FeignClientFactoryBean
|
||||
}
|
||||
|
||||
public Class<?> getFallbackFactory() {
|
||||
return this.fallbackFactory;
|
||||
return fallbackFactory;
|
||||
}
|
||||
|
||||
public void setFallbackFactory(Class<?> fallbackFactory) {
|
||||
@@ -412,32 +474,32 @@ class FeignClientFactoryBean
|
||||
return false;
|
||||
}
|
||||
FeignClientFactoryBean that = (FeignClientFactoryBean) o;
|
||||
return Objects.equals(this.applicationContext, that.applicationContext)
|
||||
&& this.decode404 == that.decode404
|
||||
&& 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.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("applicationContext=")
|
||||
.append(this.applicationContext).append(", ").append("fallback=")
|
||||
.append(this.fallback).append(", ").append("fallbackFactory=")
|
||||
.append(this.fallbackFactory).append("}").toString();
|
||||
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
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+53
-5
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
@@ -26,18 +26,24 @@ import feign.Logger;
|
||||
import feign.Retryer;
|
||||
import feign.codec.Decoder;
|
||||
import feign.codec.Encoder;
|
||||
import feign.form.MultipartFormContentProcessor;
|
||||
import feign.form.spring.SpringFormEncoder;
|
||||
import feign.optionals.OptionalDecoder;
|
||||
|
||||
import org.springframework.beans.factory.ObjectFactory;
|
||||
import org.springframework.beans.factory.ObjectProvider;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
|
||||
import org.springframework.boot.autoconfigure.data.web.SpringDataWebProperties;
|
||||
import org.springframework.boot.autoconfigure.http.HttpMessageConverters;
|
||||
import org.springframework.cloud.openfeign.clientconfig.FeignClientConfigurer;
|
||||
import org.springframework.cloud.openfeign.support.AbstractFormWriter;
|
||||
import org.springframework.cloud.openfeign.support.PageJacksonModule;
|
||||
import org.springframework.cloud.openfeign.support.PageableSpringEncoder;
|
||||
import org.springframework.cloud.openfeign.support.ResponseEntityDecoder;
|
||||
import org.springframework.cloud.openfeign.support.SortJacksonModule;
|
||||
import org.springframework.cloud.openfeign.support.SpringDecoder;
|
||||
import org.springframework.cloud.openfeign.support.SpringEncoder;
|
||||
import org.springframework.cloud.openfeign.support.SpringMvcContract;
|
||||
@@ -48,9 +54,12 @@ import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.format.support.DefaultFormattingConversionService;
|
||||
import org.springframework.format.support.FormattingConversionService;
|
||||
|
||||
import static feign.form.ContentType.MULTIPART;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
* @author Venil Noronha
|
||||
* @author Darren Foong
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class FeignClientsConfiguration {
|
||||
@@ -80,16 +89,18 @@ public class FeignClientsConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnMissingClass("org.springframework.data.domain.Pageable")
|
||||
public Encoder feignEncoder() {
|
||||
return new SpringEncoder(this.messageConverters);
|
||||
public Encoder feignEncoder(ObjectProvider<AbstractFormWriter> formWriterProvider) {
|
||||
return springEncoder(formWriterProvider);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnClass(name = "org.springframework.data.domain.Pageable")
|
||||
@ConditionalOnMissingBean
|
||||
public Encoder feignEncoderPageable() {
|
||||
public Encoder feignEncoderPageable(
|
||||
ObjectProvider<AbstractFormWriter> formWriterProvider) {
|
||||
PageableSpringEncoder encoder = new PageableSpringEncoder(
|
||||
new SpringEncoder(this.messageConverters));
|
||||
springEncoder(formWriterProvider));
|
||||
|
||||
if (springDataWebProperties != null) {
|
||||
encoder.setPageParameter(
|
||||
springDataWebProperties.getPageable().getPageParameter());
|
||||
@@ -141,4 +152,41 @@ public class FeignClientsConfiguration {
|
||||
return new PageJacksonModule();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnClass(name = "org.springframework.data.domain.Page")
|
||||
public Module sortModule() {
|
||||
return new SortJacksonModule();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(FeignClientConfigurer.class)
|
||||
public FeignClientConfigurer feignClientConfigurer() {
|
||||
return new FeignClientConfigurer() {
|
||||
};
|
||||
}
|
||||
|
||||
private Encoder springEncoder(ObjectProvider<AbstractFormWriter> formWriterProvider) {
|
||||
AbstractFormWriter formWriter = formWriterProvider.getIfAvailable();
|
||||
|
||||
if (formWriter != null) {
|
||||
return new SpringEncoder(new SpringPojoFormEncoder(formWriter),
|
||||
this.messageConverters);
|
||||
}
|
||||
else {
|
||||
return new SpringEncoder(new SpringFormEncoder(), this.messageConverters);
|
||||
}
|
||||
}
|
||||
|
||||
private class SpringPojoFormEncoder extends SpringFormEncoder {
|
||||
|
||||
SpringPojoFormEncoder(AbstractFormWriter formWriter) {
|
||||
super();
|
||||
|
||||
MultipartFormContentProcessor processor = (MultipartFormContentProcessor) getContentProcessor(
|
||||
MULTIPART);
|
||||
processor.addFirstWriter(formWriter);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
@@ -27,6 +27,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
@@ -242,9 +243,10 @@ class FeignClientsRegistrar
|
||||
|
||||
String alias = contextId + "FeignClient";
|
||||
AbstractBeanDefinition beanDefinition = definition.getBeanDefinition();
|
||||
beanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, className);
|
||||
|
||||
boolean primary = (Boolean) attributes.get("primary"); // has a default, won't be
|
||||
// null
|
||||
// has a default, won't be null
|
||||
boolean primary = (Boolean) attributes.get("primary");
|
||||
|
||||
beanDefinition.setPrimary(primary);
|
||||
|
||||
|
||||
+22
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
@@ -16,7 +16,12 @@
|
||||
|
||||
package org.springframework.cloud.openfeign;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactoryUtils;
|
||||
import org.springframework.cloud.context.named.NamedContextFactory;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* A factory that creates instances of feign classes. It creates a Spring
|
||||
@@ -24,6 +29,7 @@ import org.springframework.cloud.context.named.NamedContextFactory;
|
||||
*
|
||||
* @author Spencer Gibb
|
||||
* @author Dave Syer
|
||||
* @author Matt King
|
||||
*/
|
||||
public class FeignContext extends NamedContextFactory<FeignClientSpecification> {
|
||||
|
||||
@@ -31,4 +37,19 @@ public class FeignContext extends NamedContextFactory<FeignClientSpecification>
|
||||
super(FeignClientsConfiguration.class, "feign", "feign.client.name");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public <T> T getInstanceWithoutAncestors(String name, Class<T> type) {
|
||||
try {
|
||||
return BeanFactoryUtils.beanOfType(getContext(name), type);
|
||||
}
|
||||
catch (BeansException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public <T> Map<String, T> getInstancesWithoutAncestors(String name, Class<T> type) {
|
||||
return getContext(name).getBeansOfType(type);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016-2019 the original author or authors.
|
||||
* Copyright 2016-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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
@@ -22,7 +22,7 @@ import feign.Target;
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
interface Targeter {
|
||||
public interface Targeter {
|
||||
|
||||
<T> T target(FeignClientFactoryBean factory, Feign.Builder feign,
|
||||
FeignContext context, Target.HardCodedTarget<T> target);
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.clientconfig;
|
||||
|
||||
/**
|
||||
* Additional Feign Client configuration that are not included in
|
||||
* {@link org.springframework.cloud.openfeign.FeignClient}.
|
||||
*
|
||||
* @author Matt King
|
||||
*/
|
||||
public interface FeignClientConfigurer {
|
||||
|
||||
/**
|
||||
* @return whether to mark the feign proxy as a primary bean. Defaults to true.
|
||||
*/
|
||||
default boolean primary() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* FALSE will only apply configurations from classes listed in
|
||||
* <code>configuration()</code>. Will still use parent instance of
|
||||
* {@link feign.codec.Decoder}, {@link feign.codec.Encoder}, and
|
||||
* {@link feign.Contract} if none are provided.
|
||||
* @return weather to inherit parent context for client configuration.
|
||||
*/
|
||||
default boolean inheritParentConfiguration() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+2
-6
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
@@ -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 {
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016-2019 the original author or authors.
|
||||
* Copyright 2016-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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+82
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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 java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import feign.codec.EncodeException;
|
||||
import feign.form.multipart.AbstractWriter;
|
||||
import feign.form.multipart.Output;
|
||||
import feign.form.util.PojoUtil;
|
||||
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import static feign.form.ContentProcessor.CRLF;
|
||||
|
||||
/**
|
||||
* @author Darren Foong
|
||||
*/
|
||||
public abstract class AbstractFormWriter extends AbstractWriter {
|
||||
|
||||
@Override
|
||||
public boolean isApplicable(Object object) {
|
||||
return !isTypeOrCollection(object, o -> o instanceof MultipartFile)
|
||||
&& isTypeOrCollection(object, PojoUtil::isUserPojo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(Output output, String key, Object object) throws EncodeException {
|
||||
try {
|
||||
String string = new StringBuilder()
|
||||
.append("Content-Disposition: form-data; name=\"").append(key)
|
||||
.append('"').append(CRLF).append("Content-Type: ")
|
||||
.append(getContentType()).append("; charset=")
|
||||
.append(output.getCharset().name()).append(CRLF).append(CRLF)
|
||||
.append(writeAsString(object)).toString();
|
||||
|
||||
output.write(string);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new EncodeException(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract MediaType getContentType();
|
||||
|
||||
protected abstract String writeAsString(Object object) throws IOException;
|
||||
|
||||
private boolean isTypeOrCollection(Object object, Predicate<Object> isType) {
|
||||
if (object.getClass().isArray()) {
|
||||
Object[] array = (Object[]) object;
|
||||
|
||||
return array.length > 1 && isType.test(array[0]);
|
||||
}
|
||||
else if (object instanceof Iterable) {
|
||||
Iterable<?> iterable = (Iterable<?>) object;
|
||||
Iterator<?> iterator = iterable.iterator();
|
||||
|
||||
return iterator.hasNext() && isType.test(iterator.next());
|
||||
}
|
||||
else {
|
||||
return isType.test(object);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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 java.io.IOException;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author Darren Foong
|
||||
*/
|
||||
@Component
|
||||
public class JsonFormWriter extends AbstractFormWriter {
|
||||
|
||||
@Autowired
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@Override
|
||||
protected MediaType getContentType() {
|
||||
return MediaType.APPLICATION_JSON;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String writeAsString(Object object) throws IOException {
|
||||
return objectMapper.writeValueAsString(object);
|
||||
}
|
||||
|
||||
}
|
||||
+15
-7
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* 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.
|
||||
@@ -33,7 +33,7 @@ import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
|
||||
/**
|
||||
* This jackson module provides support to deserialize spring {@link Page} objects.
|
||||
* This Jackson module provides support to deserialize Spring {@link Page} objects.
|
||||
*
|
||||
* @author Pascal Büttiker
|
||||
*/
|
||||
@@ -64,10 +64,18 @@ public class PageJacksonModule extends Module {
|
||||
private final Page<T> delegate;
|
||||
|
||||
SimplePageImpl(@JsonProperty("content") List<T> content,
|
||||
@JsonProperty("page") int number, @JsonProperty("size") int size,
|
||||
@JsonProperty("totalElements") long totalElements) {
|
||||
delegate = new PageImpl<>(content, PageRequest.of(number, size),
|
||||
totalElements);
|
||||
@JsonProperty("number") int number, @JsonProperty("size") int size,
|
||||
@JsonProperty("totalElements") long totalElements,
|
||||
@JsonProperty("sort") Sort sort) {
|
||||
PageRequest pageRequest;
|
||||
if (sort != null) {
|
||||
pageRequest = PageRequest.of(number, size, sort);
|
||||
}
|
||||
else {
|
||||
pageRequest = PageRequest.of(number, size);
|
||||
}
|
||||
delegate = new PageImpl<>(content, pageRequest, totalElements);
|
||||
|
||||
}
|
||||
|
||||
@JsonProperty
|
||||
@@ -82,7 +90,7 @@ public class PageJacksonModule extends Module {
|
||||
return delegate.getTotalElements();
|
||||
}
|
||||
|
||||
@JsonProperty("page")
|
||||
@JsonProperty
|
||||
@Override
|
||||
public int getNumber() {
|
||||
return delegate.getNumber();
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2018 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+56
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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 com.fasterxml.jackson.core.Version;
|
||||
import com.fasterxml.jackson.databind.Module;
|
||||
import com.fasterxml.jackson.databind.module.SimpleDeserializers;
|
||||
import com.fasterxml.jackson.databind.module.SimpleSerializers;
|
||||
|
||||
import org.springframework.data.domain.Sort;
|
||||
|
||||
/**
|
||||
* This Jackson module provides support for serializing and deserializing for Spring
|
||||
* {@link Sort} object.
|
||||
*
|
||||
* @author Can Bezmen
|
||||
*/
|
||||
public class SortJacksonModule extends Module {
|
||||
|
||||
@Override
|
||||
public String getModuleName() {
|
||||
return "SortModule";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Version version() {
|
||||
return new Version(0, 1, 0, "", null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupModule(SetupContext context) {
|
||||
SimpleSerializers serializers = new SimpleSerializers();
|
||||
serializers.addSerializer(Sort.class, new SortJsonComponent.SortSerializer());
|
||||
context.addSerializers(serializers);
|
||||
|
||||
SimpleDeserializers deserializers = new SimpleDeserializers();
|
||||
deserializers.addDeserializer(Sort.class,
|
||||
new SortJsonComponent.SortDeserializer());
|
||||
context.addDeserializers(deserializers);
|
||||
}
|
||||
|
||||
}
|
||||
+95
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* 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 java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.TreeNode;
|
||||
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||
import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import feign.codec.EncodeException;
|
||||
|
||||
import org.springframework.data.domain.Sort;
|
||||
|
||||
/**
|
||||
* This class provides provides support for serializing and deserializing for Spring
|
||||
* {@link Sort} object.
|
||||
*
|
||||
* @author Can Bezmen
|
||||
*/
|
||||
public class SortJsonComponent {
|
||||
|
||||
public static class SortSerializer extends JsonSerializer<Sort> {
|
||||
|
||||
@Override
|
||||
public void serialize(Sort value, JsonGenerator gen,
|
||||
SerializerProvider serializers) throws IOException {
|
||||
gen.writeStartArray();
|
||||
value.iterator().forEachRemaining(v -> {
|
||||
try {
|
||||
gen.writeObject(v);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new EncodeException("Couldn't serialize object " + v);
|
||||
}
|
||||
});
|
||||
gen.writeEndArray();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Sort> handledType() {
|
||||
return Sort.class;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class SortDeserializer extends JsonDeserializer<Sort> {
|
||||
|
||||
@Override
|
||||
public Sort deserialize(JsonParser jsonParser,
|
||||
DeserializationContext deserializationContext) throws IOException {
|
||||
TreeNode treeNode = jsonParser.getCodec().readTree(jsonParser);
|
||||
if (treeNode.isArray()) {
|
||||
ArrayNode arrayNode = (ArrayNode) treeNode;
|
||||
List<Sort.Order> orders = new ArrayList<>();
|
||||
for (JsonNode jsonNode : arrayNode) {
|
||||
Sort.Order order = new Sort.Order(
|
||||
Sort.Direction.valueOf(jsonNode.get("direction").textValue()),
|
||||
jsonNode.get("property").textValue());
|
||||
orders.add(order);
|
||||
}
|
||||
return Sort.by(orders);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<Sort> handledType() {
|
||||
return Sort.class;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+10
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
@@ -54,16 +54,24 @@ import static org.springframework.cloud.openfeign.support.FeignUtils.getHttpHead
|
||||
* @author Scien Jus
|
||||
* @author Ahmad Mozafarnia
|
||||
* @author Aaron Whiteside
|
||||
* @author Darren Foong
|
||||
*/
|
||||
public class SpringEncoder implements Encoder {
|
||||
|
||||
private static final Log log = LogFactory.getLog(SpringEncoder.class);
|
||||
|
||||
private final SpringFormEncoder springFormEncoder = new SpringFormEncoder();
|
||||
private final SpringFormEncoder springFormEncoder;
|
||||
|
||||
private final ObjectFactory<HttpMessageConverters> messageConverters;
|
||||
|
||||
public SpringEncoder(ObjectFactory<HttpMessageConverters> messageConverters) {
|
||||
this.springFormEncoder = new SpringFormEncoder();
|
||||
this.messageConverters = messageConverters;
|
||||
}
|
||||
|
||||
public SpringEncoder(SpringFormEncoder springFormEncoder,
|
||||
ObjectFactory<HttpMessageConverters> messageConverters) {
|
||||
this.springFormEncoder = springFormEncoder;
|
||||
this.messageConverters = messageConverters;
|
||||
}
|
||||
|
||||
|
||||
+41
-18
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
@@ -28,6 +28,7 @@ import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
import feign.Contract;
|
||||
import feign.Feign;
|
||||
@@ -36,12 +37,14 @@ 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;
|
||||
import org.springframework.cloud.openfeign.annotation.RequestHeaderParameterProcessor;
|
||||
import org.springframework.cloud.openfeign.annotation.RequestParamParameterProcessor;
|
||||
import org.springframework.cloud.openfeign.annotation.RequestPartParameterProcessor;
|
||||
import org.springframework.cloud.openfeign.encoding.HttpEncoding;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
import org.springframework.core.DefaultParameterNameDiscoverer;
|
||||
@@ -54,6 +57,7 @@ import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -72,6 +76,7 @@ import static org.springframework.core.annotation.AnnotatedElementUtils.findMerg
|
||||
* @author Olga Maciaszek-Sharma
|
||||
* @author Aaron Whiteside
|
||||
* @author Artyom Romanenko
|
||||
* @author Darren Foong
|
||||
*/
|
||||
public class SpringMvcContract extends Contract.BaseContract
|
||||
implements ResourceLoaderAware {
|
||||
@@ -117,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) {
|
||||
@@ -183,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,
|
||||
@@ -209,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;
|
||||
@@ -244,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;
|
||||
@@ -276,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;
|
||||
@@ -291,11 +302,11 @@ public class SpringMvcContract extends Contract.BaseContract
|
||||
}
|
||||
}
|
||||
|
||||
if (isHttpAnnotation && data.indexToExpander().get(paramIndex) == null) {
|
||||
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);
|
||||
@@ -388,6 +399,18 @@ public class SpringMvcContract extends Contract.BaseContract
|
||||
&& parameterTypes != null && parameterTypes.length > parameterIndex;
|
||||
}
|
||||
|
||||
private boolean isMultipartFormData(MethodMetadata data) {
|
||||
Collection<String> contentTypes = data.template().headers()
|
||||
.get(HttpEncoding.CONTENT_TYPE);
|
||||
|
||||
if (contentTypes != null && !contentTypes.isEmpty()) {
|
||||
String type = contentTypes.iterator().next();
|
||||
return Objects.equals(MediaType.valueOf(type), MediaType.MULTIPART_FORM_DATA);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Not used internally anymore. Will be removed in the future.
|
||||
*/
|
||||
@@ -402,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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -417,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;
|
||||
};
|
||||
@@ -440,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
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2015 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2015 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* 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.reflect.Field;
|
||||
|
||||
import feign.Feign;
|
||||
import feign.Logger;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author Matt King
|
||||
*/
|
||||
public class FeignBuilderCustomizerTests {
|
||||
|
||||
@Test
|
||||
public void testBuilderCustomizer() {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
|
||||
FeignBuilderCustomizerTests.SampleConfiguration2.class);
|
||||
|
||||
FeignClientFactoryBean clientFactoryBean = context
|
||||
.getBean(FeignClientFactoryBean.class);
|
||||
FeignContext feignContext = context.getBean(FeignContext.class);
|
||||
|
||||
Feign.Builder builder = clientFactoryBean.feign(feignContext);
|
||||
assertFeignBuilderField(builder, "logLevel", Logger.Level.HEADERS);
|
||||
assertFeignBuilderField(builder, "decode404", true);
|
||||
|
||||
context.close();
|
||||
}
|
||||
|
||||
private void assertFeignBuilderField(Feign.Builder builder, String fieldName,
|
||||
Object expectedValue) {
|
||||
Field builderField = ReflectionUtils.findField(Feign.Builder.class, fieldName);
|
||||
ReflectionUtils.makeAccessible(builderField);
|
||||
|
||||
Object value = ReflectionUtils.getField(builderField, builder);
|
||||
assertThat(value).as("Expected value for the field '" + fieldName + "':")
|
||||
.isEqualTo(expectedValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBuildCustomizerOrdered() {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
|
||||
FeignBuilderCustomizerTests.SampleConfiguration3.class);
|
||||
|
||||
FeignClientFactoryBean clientFactoryBean = context
|
||||
.getBean(FeignClientFactoryBean.class);
|
||||
FeignContext feignContext = context.getBean(FeignContext.class);
|
||||
|
||||
Feign.Builder builder = clientFactoryBean.feign(feignContext);
|
||||
assertFeignBuilderField(builder, "logLevel", Logger.Level.FULL);
|
||||
assertFeignBuilderField(builder, "decode404", true);
|
||||
|
||||
context.close();
|
||||
}
|
||||
|
||||
private static FeignClientFactoryBean defaultFeignClientFactoryBean() {
|
||||
FeignClientFactoryBean feignClientFactoryBean = new FeignClientFactoryBean();
|
||||
feignClientFactoryBean.setContextId("test");
|
||||
feignClientFactoryBean.setName("test");
|
||||
feignClientFactoryBean.setType(FeignClientFactoryTests.TestType.class);
|
||||
feignClientFactoryBean.setPath("");
|
||||
feignClientFactoryBean.setUrl("http://some.absolute.url");
|
||||
return feignClientFactoryBean;
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(FeignClientsConfiguration.class)
|
||||
protected static class SampleConfiguration2 {
|
||||
|
||||
@Bean
|
||||
FeignContext feignContext() {
|
||||
return new FeignContext();
|
||||
}
|
||||
|
||||
@Bean
|
||||
FeignClientProperties feignClientProperties() {
|
||||
return new FeignClientProperties();
|
||||
}
|
||||
|
||||
@Bean
|
||||
FeignBuilderCustomizer feignBuilderCustomizer() {
|
||||
return builder -> builder.logLevel(Logger.Level.HEADERS);
|
||||
}
|
||||
|
||||
@Bean
|
||||
FeignBuilderCustomizer feignBuilderCustomizer2() {
|
||||
return Feign.Builder::decode404;
|
||||
}
|
||||
|
||||
@Bean
|
||||
FeignClientFactoryBean feignClientFactoryBean() {
|
||||
return defaultFeignClientFactoryBean();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(FeignClientsConfiguration.class)
|
||||
protected static class SampleConfiguration3 {
|
||||
|
||||
@Bean
|
||||
FeignContext feignContext() {
|
||||
return new FeignContext();
|
||||
}
|
||||
|
||||
@Bean
|
||||
FeignClientProperties feignClientProperties() {
|
||||
return new FeignClientProperties();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(1)
|
||||
FeignBuilderCustomizer feignBuilderCustomizer() {
|
||||
return builder -> builder.logLevel(Logger.Level.HEADERS);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Order(2)
|
||||
FeignBuilderCustomizer feignBuilderCustomizer1() {
|
||||
return builder -> builder.logLevel(Logger.Level.FULL);
|
||||
}
|
||||
|
||||
@Bean
|
||||
FeignBuilderCustomizer feignBuilderCustomizer2() {
|
||||
return Feign.Builder::decode404;
|
||||
}
|
||||
|
||||
@Bean
|
||||
FeignClientFactoryBean feignClientFactoryBean() {
|
||||
return defaultFeignClientFactoryBean();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+21
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
@@ -142,6 +142,26 @@ public class FeignClientBuilderTests {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forType_clientFactoryBeanProvided() {
|
||||
// when:
|
||||
final FeignClientBuilder.Builder builder = this.feignClientBuilder
|
||||
.forType(TestFeignClient.class, new FeignClientFactoryBean(),
|
||||
"TestClient")
|
||||
.decode404(true).path("Path/").url("Url/").contextId("TestContext");
|
||||
|
||||
// then:
|
||||
assertFactoryBeanField(builder, "applicationContext", this.applicationContext);
|
||||
assertFactoryBeanField(builder, "type", TestFeignClient.class);
|
||||
assertFactoryBeanField(builder, "name", "TestClient");
|
||||
assertFactoryBeanField(builder, "contextId", "TestContext");
|
||||
|
||||
// and:
|
||||
assertFactoryBeanField(builder, "url", "http://Url/");
|
||||
assertFactoryBeanField(builder, "path", "/Path");
|
||||
assertFactoryBeanField(builder, "decode404", true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forType_build() {
|
||||
// given:
|
||||
|
||||
+3
-1
@@ -90,7 +90,9 @@ public class FeignClientErrorDecoderTests {
|
||||
Map<Method, InvocationHandlerFactory.MethodHandler> dispatch = (Map<Method, InvocationHandlerFactory.MethodHandler>) ReflectionTestUtils
|
||||
.getField(invocationHandler, "dispatch");
|
||||
Method key = new ArrayList<>(dispatch.keySet()).get(0);
|
||||
return ReflectionTestUtils.getField(dispatch.get(key), "errorDecoder");
|
||||
return ReflectionTestUtils.getField(
|
||||
ReflectionTestUtils.getField(dispatch.get(key), "asyncResponseHandler"),
|
||||
"errorDecoder");
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
|
||||
+4
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
@@ -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
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+149
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.reflect.Field;
|
||||
import java.util.List;
|
||||
|
||||
import feign.Feign;
|
||||
import feign.Logger;
|
||||
import feign.RequestInterceptor;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
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.clientconfig.FeignClientConfigurer;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* @author matt king
|
||||
*/
|
||||
@DirtiesContext
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@SpringBootTest(classes = FeignClientUsingConfigurerTest.Application.class, value = {
|
||||
"feign.client.config.default.loggerLevel=full",
|
||||
"feign.client.config.default.requestInterceptors[0]=org.springframework.cloud.openfeign.FeignClientUsingPropertiesTests.FooRequestInterceptor",
|
||||
"feign.client.config.default.requestInterceptors[1]=org.springframework.cloud.openfeign.FeignClientUsingPropertiesTests.BarRequestInterceptor" })
|
||||
public class FeignClientUsingConfigurerTest {
|
||||
|
||||
private static final String BEAN_NAME_PREFIX = "&org.springframework.cloud.openfeign.FeignClientUsingConfigurerTest$";
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
@Autowired
|
||||
private FeignContext context;
|
||||
|
||||
@Test
|
||||
public void testFeignClient() {
|
||||
FeignClientFactoryBean factoryBean = (FeignClientFactoryBean) applicationContext
|
||||
.getBean(BEAN_NAME_PREFIX + "TestFeignClient");
|
||||
Feign.Builder builder = factoryBean.feign(context);
|
||||
|
||||
List<RequestInterceptor> interceptors = (List) getBuilderValue(builder,
|
||||
"requestInterceptors");
|
||||
assertThat(interceptors.size()).as("interceptors not set").isEqualTo(3);
|
||||
assertThat(getBuilderValue(builder, "logLevel")).as("log level not set")
|
||||
.isEqualTo(Logger.Level.FULL);
|
||||
}
|
||||
|
||||
private Object getBuilderValue(Feign.Builder builder, String member) {
|
||||
Field builderField = ReflectionUtils.findField(Feign.Builder.class, member);
|
||||
ReflectionUtils.makeAccessible(builderField);
|
||||
|
||||
return ReflectionUtils.getField(builderField, builder);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoInheritFeignClient() {
|
||||
FeignClientFactoryBean factoryBean = (FeignClientFactoryBean) applicationContext
|
||||
.getBean(BEAN_NAME_PREFIX + "NoInheritFeignClient");
|
||||
Feign.Builder builder = factoryBean.feign(context);
|
||||
|
||||
List<RequestInterceptor> interceptors = (List) getBuilderValue(builder,
|
||||
"requestInterceptors");
|
||||
|
||||
assertThat(interceptors).as("interceptors not set").isEmpty();
|
||||
assertThat(factoryBean.isInheritParentContext())
|
||||
.as("is inheriting from parent configuration").isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNoInheritFeignClient_ignoreProperties() {
|
||||
FeignClientFactoryBean factoryBean = (FeignClientFactoryBean) applicationContext
|
||||
.getBean(BEAN_NAME_PREFIX + "NoInheritFeignClient");
|
||||
Feign.Builder builder = factoryBean.feign(context);
|
||||
|
||||
assertThat(getBuilderValue(builder, "logLevel")).as("log level not set")
|
||||
.isEqualTo(Logger.Level.HEADERS);
|
||||
}
|
||||
|
||||
@EnableAutoConfiguration
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableFeignClients(clients = { TestFeignClient.class, NoInheritFeignClient.class })
|
||||
protected static class Application {
|
||||
|
||||
@Bean
|
||||
public RequestInterceptor requestInterceptor() {
|
||||
return requestTemplate -> {
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class NoInheritConfiguration {
|
||||
|
||||
@Bean
|
||||
public Logger.Level logLevel() {
|
||||
return Logger.Level.HEADERS;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FeignClientConfigurer feignClientConfigurer() {
|
||||
return new FeignClientConfigurer() {
|
||||
|
||||
@Override
|
||||
public boolean inheritParentConfiguration() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@FeignClient("testFeignClient")
|
||||
interface TestFeignClient {
|
||||
|
||||
}
|
||||
|
||||
@FeignClient(name = "noInheritFeignClient",
|
||||
configuration = NoInheritConfiguration.class)
|
||||
interface NoInheritFeignClient {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+83
-25
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
@@ -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
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright 2013-2019 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.util.Collection;
|
||||
|
||||
import feign.Logger;
|
||||
import feign.RequestInterceptor;
|
||||
import org.assertj.core.util.Lists;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
public class FeignContextTest {
|
||||
|
||||
@Test
|
||||
public void getInstanceWithoutAncestors_verifyNullForMissing() {
|
||||
AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext();
|
||||
parent.refresh();
|
||||
|
||||
FeignContext feignContext = new FeignContext();
|
||||
feignContext.setApplicationContext(parent);
|
||||
feignContext.setConfigurations(
|
||||
Lists.newArrayList(getSpec("empty", EmptyConfiguration.class)));
|
||||
|
||||
Logger.Level level = feignContext.getInstanceWithoutAncestors("empty",
|
||||
Logger.Level.class);
|
||||
|
||||
assertThat(level).as("Logger was not null").isNull();
|
||||
}
|
||||
|
||||
private FeignClientSpecification getSpec(String name, Class<?> configClass) {
|
||||
return new FeignClientSpecification(name, new Class[] { configClass });
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getInstancesWithoutAncestors_verifyEmptyForMissing() {
|
||||
AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext();
|
||||
parent.refresh();
|
||||
|
||||
FeignContext feignContext = new FeignContext();
|
||||
feignContext.setApplicationContext(parent);
|
||||
feignContext.setConfigurations(
|
||||
Lists.newArrayList(getSpec("empty", EmptyConfiguration.class)));
|
||||
|
||||
Collection<RequestInterceptor> interceptors = feignContext
|
||||
.getInstancesWithoutAncestors("empty", RequestInterceptor.class).values();
|
||||
|
||||
assertThat(interceptors).as("Interceptors is not empty").isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getInstanceWithoutAncestors() {
|
||||
AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext();
|
||||
parent.refresh();
|
||||
|
||||
FeignContext feignContext = new FeignContext();
|
||||
feignContext.setApplicationContext(parent);
|
||||
feignContext.setConfigurations(
|
||||
Lists.newArrayList(getSpec("demo", DemoConfiguration.class)));
|
||||
|
||||
Logger.Level level = feignContext.getInstanceWithoutAncestors("demo",
|
||||
Logger.Level.class);
|
||||
|
||||
assertThat(level).isEqualTo(Logger.Level.FULL);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getInstancesWithoutAncestors() {
|
||||
AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext();
|
||||
parent.refresh();
|
||||
|
||||
FeignContext feignContext = new FeignContext();
|
||||
feignContext.setApplicationContext(parent);
|
||||
feignContext.setConfigurations(
|
||||
Lists.newArrayList(getSpec("demo", DemoConfiguration.class)));
|
||||
|
||||
Collection<RequestInterceptor> interceptors = feignContext
|
||||
.getInstancesWithoutAncestors("demo", RequestInterceptor.class).values();
|
||||
|
||||
assertThat(interceptors.size()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(FeignClientsConfiguration.class)
|
||||
protected static class EmptyConfiguration {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@Import(FeignClientsConfiguration.class)
|
||||
protected static class DemoConfiguration {
|
||||
|
||||
@Bean
|
||||
public Logger.Level loggerLevel() {
|
||||
return Logger.Level.FULL;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RequestInterceptor requestInterceptor() {
|
||||
return (requestTemplate) -> {
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016-2019 the original author or authors.
|
||||
* Copyright 2016-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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
@@ -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);
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+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();
|
||||
}
|
||||
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+11
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2015 the original author or authors.
|
||||
* 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.
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.cloud.openfeign.encoding;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@@ -78,6 +80,14 @@ public class FeignPageableEncodingTests {
|
||||
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
|
||||
assertThat(response.getBody()).isNotNull();
|
||||
assertThat(pageable.getPageSize()).isEqualTo(response.getBody().getSize());
|
||||
assertThat(response.getBody().getPageable().getSort()).hasSize(1);
|
||||
Optional<Sort.Order> optionalOrder = response.getBody().getPageable().getSort()
|
||||
.get().findFirst();
|
||||
if (optionalOrder.isPresent()) {
|
||||
Sort.Order order = optionalOrder.get();
|
||||
assertThat(order.getDirection()).isEqualTo(Sort.Direction.ASC);
|
||||
assertThat(order.getProperty()).isEqualTo("sortProperty");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2019 the original author or authors.
|
||||
* 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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016-2019 the original author or authors.
|
||||
* Copyright 2016-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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016-2019 the original author or authors.
|
||||
* Copyright 2016-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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016-2019 the original author or authors.
|
||||
* Copyright 2016-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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016-2019 the original author or authors.
|
||||
* Copyright 2016-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.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2016-2019 the original author or authors.
|
||||
* Copyright 2016-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.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user