Compare commits
25
Commits
v2.2.8.RELEASE
...
2.2.x
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
161789e33a | ||
|
|
650b14ac22 | ||
|
|
17d0161faf | ||
|
|
d6783a6f1e | ||
|
|
1275875ddb | ||
|
|
c4b9492a9b | ||
|
|
3acf5f9e92 | ||
|
|
e9e38d0274 | ||
|
|
28b50401c5 | ||
|
|
6479db0a54 | ||
|
|
f7e490c466 | ||
|
|
d60cda824d | ||
|
|
190f5a9083 | ||
|
|
1005749eb5 | ||
|
|
df1f982046 | ||
|
|
baf7cf95f2 | ||
|
|
00ea88c67f | ||
|
|
d897b18e16 | ||
|
|
8c08204c78 | ||
|
|
2f43715f6f | ||
|
|
421df91a80 | ||
|
|
ec1f2ad5bb | ||
|
|
5baa8c8ed5 | ||
|
|
0684ee4bc2 | ||
|
|
0b34d89adc |
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
Spring Cloud is released under the non-restrictive Apache 2.0 license,
|
Spring Cloud is released under the non-restrictive Apache 2.0 license,
|
||||||
and follows a very standard Github development process, using Github
|
and follows a very standard Github development process, using Github
|
||||||
tracker for issues and merging pull requests into master. If you want
|
tracker for issues and merging pull requests into main. If you want
|
||||||
to contribute even something trivial please do not hesitate, but
|
to contribute even something trivial please do not hesitate, but
|
||||||
follow the guidelines below.
|
follow the guidelines below.
|
||||||
|
|
||||||
@@ -17,7 +17,7 @@ given the ability to merge pull requests.
|
|||||||
|
|
||||||
## Code of Conduct
|
## Code of Conduct
|
||||||
This project adheres to the Contributor Covenant [code of
|
This project adheres to the Contributor Covenant [code of
|
||||||
conduct](https://github.com/spring-cloud/spring-cloud-build/blob/master/docs/src/main/asciidoc/code-of-conduct.adoc). By participating, you are expected to uphold this code. Please report
|
conduct](https://github.com/spring-cloud/spring-cloud-build/blob/main/docs/src/main/asciidoc/code-of-conduct.adoc). By participating, you are expected to uphold this code. Please report
|
||||||
unacceptable behavior to spring-code-of-conduct@pivotal.io.
|
unacceptable behavior to spring-code-of-conduct@pivotal.io.
|
||||||
|
|
||||||
## Code Conventions and Housekeeping
|
## Code Conventions and Housekeeping
|
||||||
@@ -27,7 +27,7 @@ added after the original pull request but before a merge.
|
|||||||
* Use the Spring Framework code format conventions. If you use Eclipse
|
* Use the Spring Framework code format conventions. If you use Eclipse
|
||||||
you can import formatter settings using the
|
you can import formatter settings using the
|
||||||
`eclipse-code-formatter.xml` file from the
|
`eclipse-code-formatter.xml` file from the
|
||||||
[Spring Cloud Build](https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-dependencies-parent/eclipse-code-formatter.xml) project. If using IntelliJ, you can use the
|
[Spring Cloud Build](https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/main/spring-cloud-dependencies-parent/eclipse-code-formatter.xml) project. If using IntelliJ, you can use the
|
||||||
[Eclipse Code Formatter Plugin](https://plugins.jetbrains.com/plugin/6546) to import the same file.
|
[Eclipse Code Formatter Plugin](https://plugins.jetbrains.com/plugin/6546) to import the same file.
|
||||||
* Make sure all new `.java` files to have a simple Javadoc class comment with at least an
|
* Make sure all new `.java` files to have a simple Javadoc class comment with at least an
|
||||||
`@author` tag identifying you, and preferably at least a paragraph on what the class is
|
`@author` tag identifying you, and preferably at least a paragraph on what the class is
|
||||||
@@ -38,7 +38,7 @@ added after the original pull request but before a merge.
|
|||||||
than cosmetic changes).
|
than cosmetic changes).
|
||||||
* Add some Javadocs and, if you change the namespace, some XSD doc elements.
|
* Add some Javadocs and, if you change the namespace, some XSD doc elements.
|
||||||
* A few unit tests would help a lot as well -- someone has to do it.
|
* A few unit tests would help a lot as well -- someone has to do it.
|
||||||
* If no-one else is using your branch, please rebase it against the current master (or
|
* If no-one else is using your branch, please rebase it against the current main (or
|
||||||
other target branch in the main project).
|
other target branch in the main project).
|
||||||
* When writing a commit message please follow [these conventions](https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html),
|
* When writing a commit message please follow [these conventions](https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html),
|
||||||
if you are fixing an existing issue please add `Fixes gh-XXXX` at the end of the commit
|
if you are fixing an existing issue please add `Fixes gh-XXXX` at the end of the commit
|
||||||
|
|||||||
+4
-18
@@ -7,7 +7,7 @@ Edit the files in the src/main/asciidoc/ directory instead.
|
|||||||
|
|
||||||
image::https://github.com/spring-cloud/spring-cloud-openfeign/workflows/Build/badge.svg?branch=2.2.x&style=svg["Build",link="https://github.com/spring-cloud/spring-cloud-openfeign/actions"]
|
image::https://github.com/spring-cloud/spring-cloud-openfeign/workflows/Build/badge.svg?branch=2.2.x&style=svg["Build",link="https://github.com/spring-cloud/spring-cloud-openfeign/actions"]
|
||||||
|
|
||||||
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"]
|
image:https://codecov.io/gh/spring-cloud/spring-cloud-openfeign/branch/main/graph/badge.svg["Codecov", link="https://codecov.io/gh/spring-cloud/spring-cloud-openfeign"]
|
||||||
|
|
||||||
image:https://api.codacy.com/project/badge/Grade/97b04c4e609c4b4f86b415e4437a6484["Codacy code quality", link="https://www.codacy.com/app/Spring-Cloud/spring-cloud-openfeign?utm_source=github.com&utm_medium=referral&utm_content=spring-cloud/spring-cloud-openfeign&utm_campaign=Badge_Grade"]
|
image:https://api.codacy.com/project/badge/Grade/97b04c4e609c4b4f86b415e4437a6484["Codacy code quality", link="https://www.codacy.com/app/Spring-Cloud/spring-cloud-openfeign?utm_source=github.com&utm_medium=referral&utm_content=spring-cloud/spring-cloud-openfeign&utm_campaign=Badge_Grade"]
|
||||||
|
|
||||||
@@ -66,23 +66,9 @@ the `.mvn` configuration, so if you find you have to do it to make a
|
|||||||
build succeed, please raise a ticket to get the settings added to
|
build succeed, please raise a ticket to get the settings added to
|
||||||
source control.
|
source control.
|
||||||
|
|
||||||
For hints on how to build the project look in `.travis.yml` if there
|
The projects that require middleware (i.e. Redis) for testing generally
|
||||||
is one. There should be a "script" and maybe "install" command. Also
|
require that a local instance of [Docker](https://www.docker.com/get-started) is installed and running.
|
||||||
look at the "services" section to see if any services need to be
|
|
||||||
running locally (e.g. mongo or rabbit). Ignore the git-related bits
|
|
||||||
that you might find in "before_install" since they're related to setting git
|
|
||||||
credentials and you already have those.
|
|
||||||
|
|
||||||
The projects that require middleware generally include a
|
|
||||||
`docker-compose.yml`, so consider using
|
|
||||||
https://docs.docker.com/compose/[Docker Compose] to run the middeware servers
|
|
||||||
in Docker containers. See the README in the
|
|
||||||
https://github.com/spring-cloud-samples/scripts[scripts demo
|
|
||||||
repository] for specific instructions about the common cases of mongo,
|
|
||||||
rabbit and redis.
|
|
||||||
|
|
||||||
NOTE: If all else fails, build with the command from `.travis.yml` (usually
|
|
||||||
`./mvnw install`).
|
|
||||||
|
|
||||||
=== Documentation
|
=== Documentation
|
||||||
|
|
||||||
@@ -319,4 +305,4 @@ IMPORTANT: Remember to set the `Scan Scope` to `All sources` since we apply chec
|
|||||||
|
|
||||||
== License
|
== License
|
||||||
|
|
||||||
The project license file is available https://raw.githubusercontent.com/spring-cloud/spring-cloud-openfeign/master/LICENSE.txt[here].
|
The project license file is available https://raw.githubusercontent.com/spring-cloud/spring-cloud-openfeign/main/LICENSE.txt[here].
|
||||||
|
|||||||
+1
-1
@@ -6,7 +6,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.cloud</groupId>
|
<groupId>org.springframework.cloud</groupId>
|
||||||
<artifactId>spring-cloud-openfeign</artifactId>
|
<artifactId>spring-cloud-openfeign</artifactId>
|
||||||
<version>2.2.8.RELEASE</version>
|
<version>2.2.11.BUILD-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>spring-cloud-openfeign-docs</artifactId>
|
<artifactId>spring-cloud-openfeign-docs</artifactId>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
image::https://github.com/spring-cloud/spring-cloud-openfeign/workflows/Build/badge.svg?branch=2.2.x&style=svg["Build",link="https://github.com/spring-cloud/spring-cloud-openfeign/actions"]
|
image::https://github.com/spring-cloud/spring-cloud-openfeign/workflows/Build/badge.svg?branch=2.2.x&style=svg["Build",link="https://github.com/spring-cloud/spring-cloud-openfeign/actions"]
|
||||||
|
|
||||||
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"]
|
image:https://codecov.io/gh/spring-cloud/spring-cloud-openfeign/branch/main/graph/badge.svg["Codecov", link="https://codecov.io/gh/spring-cloud/spring-cloud-openfeign"]
|
||||||
|
|
||||||
image:https://api.codacy.com/project/badge/Grade/97b04c4e609c4b4f86b415e4437a6484["Codacy code quality", link="https://www.codacy.com/app/Spring-Cloud/spring-cloud-openfeign?utm_source=github.com&utm_medium=referral&utm_content=spring-cloud/spring-cloud-openfeign&utm_campaign=Badge_Grade"]
|
image:https://api.codacy.com/project/badge/Grade/97b04c4e609c4b4f86b415e4437a6484["Codacy code quality", link="https://www.codacy.com/app/Spring-Cloud/spring-cloud-openfeign?utm_source=github.com&utm_medium=referral&utm_content=spring-cloud/spring-cloud-openfeign&utm_campaign=Badge_Grade"]
|
||||||
|
|
||||||
@@ -14,12 +14,12 @@ include::intro.adoc[]
|
|||||||
|
|
||||||
== Building
|
== Building
|
||||||
|
|
||||||
include::https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/docs/src/main/asciidoc/building-jdk8.adoc[]
|
include::https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/main/docs/src/main/asciidoc/building-jdk8.adoc[]
|
||||||
|
|
||||||
== Contributing
|
== Contributing
|
||||||
|
|
||||||
include::https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/docs/src/main/asciidoc/contributing.adoc[]
|
include::https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/main/docs/src/main/asciidoc/contributing.adoc[]
|
||||||
|
|
||||||
== License
|
== License
|
||||||
|
|
||||||
The project license file is available https://raw.githubusercontent.com/spring-cloud/spring-cloud-openfeign/master/LICENSE.txt[here].
|
The project license file is available https://raw.githubusercontent.com/spring-cloud/spring-cloud-openfeign/main/LICENSE.txt[here].
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ function check_if_anything_to_sync() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function retrieve_current_branch() {
|
function retrieve_current_branch() {
|
||||||
# Code getting the name of the current branch. For master we want to publish as we did until now
|
# Code getting the name of the current branch. For main we want to publish as we did until now
|
||||||
# https://stackoverflow.com/questions/1593051/how-to-programmatically-determine-the-current-checked-out-git-branch
|
# https://stackoverflow.com/questions/1593051/how-to-programmatically-determine-the-current-checked-out-git-branch
|
||||||
# If there is a branch already passed will reuse it - otherwise will try to find it
|
# If there is a branch already passed will reuse it - otherwise will try to find it
|
||||||
CURRENT_BRANCH=${BRANCH}
|
CURRENT_BRANCH=${BRANCH}
|
||||||
@@ -134,8 +134,8 @@ function add_docs_from_target() {
|
|||||||
|
|
||||||
# Copies the docs by using the retrieved properties from Maven build
|
# Copies the docs by using the retrieved properties from Maven build
|
||||||
function copy_docs_for_current_version() {
|
function copy_docs_for_current_version() {
|
||||||
if [[ "${CURRENT_BRANCH}" == "master" ]] ; then
|
if [[ "${CURRENT_BRANCH}" == "main" ]] ; then
|
||||||
echo -e "Current branch is master - will copy the current docs only to the root folder"
|
echo -e "Current branch is main - will copy the current docs only to the root folder"
|
||||||
for f in docs/target/generated-docs/*; do
|
for f in docs/target/generated-docs/*; do
|
||||||
file=${f#docs/target/generated-docs/*}
|
file=${f#docs/target/generated-docs/*}
|
||||||
if ! git ls-files -i -o --exclude-standard --directory | grep -q ^$file$; then
|
if ! git ls-files -i -o --exclude-standard --directory | grep -q ^$file$; then
|
||||||
@@ -216,7 +216,7 @@ function commit_changes_if_applicable() {
|
|||||||
git commit -a -m "Sync docs from ${CURRENT_BRANCH} to gh-pages" && COMMIT_SUCCESSFUL="yes" || echo "Failed to commit changes"
|
git commit -a -m "Sync docs from ${CURRENT_BRANCH} to gh-pages" && COMMIT_SUCCESSFUL="yes" || echo "Failed to commit changes"
|
||||||
|
|
||||||
# Uncomment the following push if you want to auto push to
|
# Uncomment the following push if you want to auto push to
|
||||||
# the gh-pages branch whenever you commit to master locally.
|
# the gh-pages branch whenever you commit to main locally.
|
||||||
# This is a little extreme. Use with care!
|
# This is a little extreme. Use with care!
|
||||||
###################################################################
|
###################################################################
|
||||||
if [[ "${COMMIT_SUCCESSFUL}" == "yes" ]] ; then
|
if [[ "${COMMIT_SUCCESSFUL}" == "yes" ]] ; then
|
||||||
@@ -249,7 +249,7 @@ The idea of this script is to update gh-pages branch with the generated docs. Wi
|
|||||||
the script will work in the following manner:
|
the script will work in the following manner:
|
||||||
|
|
||||||
- if there's no gh-pages / target for docs module then the script ends
|
- if there's no gh-pages / target for docs module then the script ends
|
||||||
- for master branch the generated docs are copied to the root of gh-pages branch
|
- for main branch the generated docs are copied to the root of gh-pages branch
|
||||||
- for any other branch (if that branch is whitelisted) a subfolder with branch name is created
|
- for any other branch (if that branch is whitelisted) a subfolder with branch name is created
|
||||||
and docs are copied there
|
and docs are copied there
|
||||||
- if the version switch is passed (-v) then a tag with (v) prefix will be retrieved and a folder
|
- if the version switch is passed (-v) then a tag with (v) prefix will be retrieved and a folder
|
||||||
@@ -327,4 +327,4 @@ build_docs_if_applicable
|
|||||||
retrieve_doc_properties
|
retrieve_doc_properties
|
||||||
stash_changes
|
stash_changes
|
||||||
add_docs_from_target
|
add_docs_from_target
|
||||||
checkout_previous_branch
|
checkout_previous_branch
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ public class WebApplication {
|
|||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
We welcome contributions. You can read more on how to contribute to the project https://github.com/spring-cloud/spring-cloud-openfeign/blob/master/README.adoc#3-contributing[here].
|
We welcome contributions. You can read more on how to contribute to the project https://github.com/spring-cloud/spring-cloud-openfeign/blob/main/README.adoc#3-contributing[here].
|
||||||
|
|
||||||
## Community Support
|
## Community Support
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ public interface StoreClient {
|
|||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
In the `@FeignClient` annotation the String value ("stores" above) is an arbitrary client name, which is used to create either a https://github.com/Netflix/ribbon[Ribbon] load-balancer (see <<spring-cloud-ribbon,below for details of Ribbon support>> and <<spring-cloud-circuitbreaker,below for details of Spring Cloud CircuitBreaker support>>) or https://github.com/spring-cloud/spring-cloud-commons/blob/master/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/ReactiveLoadBalancer.java[Spring Cloud LoadBalancer].
|
In the `@FeignClient` annotation the String value ("stores" above) is an arbitrary client name, which is used to create either a https://github.com/Netflix/ribbon[Ribbon] load-balancer (see <<spring-cloud-ribbon,below for details of Ribbon support>> and <<spring-cloud-circuitbreaker,below for details of Spring Cloud CircuitBreaker support>>) or https://github.com/spring-cloud/spring-cloud-commons/blob/main/spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/reactive/ReactiveLoadBalancer.java[Spring Cloud LoadBalancer].
|
||||||
You can also specify a URL using the `url` attribute
|
You can also specify a URL using the `url` attribute
|
||||||
(absolute value or just a hostname). The name of the bean in the
|
(absolute value or just a hostname). The name of the bean in the
|
||||||
application context is the fully qualified name of the interface.
|
application context is the fully qualified name of the interface.
|
||||||
@@ -523,10 +523,7 @@ public interface UserClient extends UserService {
|
|||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
NOTE: It is generally not advisable to share an interface between a
|
WARNING: `@FeignClient` interfaces should not be shared between server and client and annotating `@FeignClient` interfaces with `@RequestMapping` on class level is no longer supported.
|
||||||
server and a client. It introduces tight coupling, and also actually
|
|
||||||
doesn't work with Spring MVC in its current form (method parameter
|
|
||||||
mapping is not inherited).
|
|
||||||
|
|
||||||
=== Feign request/response compression
|
=== Feign request/response compression
|
||||||
|
|
||||||
|
|||||||
@@ -4,14 +4,14 @@
|
|||||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
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>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<artifactId>spring-cloud-openfeign</artifactId>
|
<artifactId>spring-cloud-openfeign</artifactId>
|
||||||
<version>2.2.8.RELEASE</version>
|
<version>2.2.11.BUILD-SNAPSHOT</version>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
<name>Spring Cloud OpenFeign</name>
|
<name>Spring Cloud OpenFeign</name>
|
||||||
<description>Spring Cloud OpenFeign</description>
|
<description>Spring Cloud OpenFeign</description>
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.cloud</groupId>
|
<groupId>org.springframework.cloud</groupId>
|
||||||
<artifactId>spring-cloud-build</artifactId>
|
<artifactId>spring-cloud-build</artifactId>
|
||||||
<version>2.3.4.RELEASE</version>
|
<version>2.3.6.BUILD-SNAPSHOT</version>
|
||||||
<relativePath/>
|
<relativePath/>
|
||||||
</parent>
|
</parent>
|
||||||
<scm>
|
<scm>
|
||||||
@@ -26,8 +26,8 @@
|
|||||||
<properties>
|
<properties>
|
||||||
<main.basedir>${basedir}</main.basedir>
|
<main.basedir>${basedir}</main.basedir>
|
||||||
<jackson.version>2.11.3</jackson.version>
|
<jackson.version>2.11.3</jackson.version>
|
||||||
<spring-cloud-commons.version>2.2.8.RELEASE</spring-cloud-commons.version>
|
<spring-cloud-commons.version>2.2.9.RELEASE</spring-cloud-commons.version>
|
||||||
<spring-cloud-netflix.version>2.2.8.RELEASE</spring-cloud-netflix.version>
|
<spring-cloud-netflix.version>2.2.9.RELEASE</spring-cloud-netflix.version>
|
||||||
|
|
||||||
<!-- Plugin versions -->
|
<!-- Plugin versions -->
|
||||||
<maven-eclipse-plugin.version>2.10</maven-eclipse-plugin.version>
|
<maven-eclipse-plugin.version>2.10</maven-eclipse-plugin.version>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.cloud</groupId>
|
<groupId>org.springframework.cloud</groupId>
|
||||||
<artifactId>spring-cloud-openfeign</artifactId>
|
<artifactId>spring-cloud-openfeign</artifactId>
|
||||||
<version>2.2.8.RELEASE</version>
|
<version>2.2.11.BUILD-SNAPSHOT</version>
|
||||||
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
<relativePath>..</relativePath> <!-- lookup parent from repository -->
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>spring-cloud-openfeign-core</artifactId>
|
<artifactId>spring-cloud-openfeign-core</artifactId>
|
||||||
|
|||||||
+4
-6
@@ -373,12 +373,10 @@ public class FeignClientFactoryBean implements FactoryBean<Object>, Initializing
|
|||||||
Feign.Builder builder = feign(context);
|
Feign.Builder builder = feign(context);
|
||||||
|
|
||||||
if (!StringUtils.hasText(url)) {
|
if (!StringUtils.hasText(url)) {
|
||||||
if (url != null && LOG.isWarnEnabled()) {
|
|
||||||
LOG.warn(
|
if (LOG.isInfoEnabled()) {
|
||||||
"The provided URL is empty. Will try picking an instance via load-balancing.");
|
LOG.info("For '" + name
|
||||||
}
|
+ "' URL not provided. Will try picking an instance via load-balancing.");
|
||||||
else if (LOG.isDebugEnabled()) {
|
|
||||||
LOG.debug("URL not provided. Will use LoadBalancer.");
|
|
||||||
}
|
}
|
||||||
if (!name.startsWith("http")) {
|
if (!name.startsWith("http")) {
|
||||||
url = "http://" + name;
|
url = "http://" + name;
|
||||||
|
|||||||
+1
-1
@@ -75,7 +75,7 @@ public class MatrixVariableParameterProcessor implements AnnotatedParameterProce
|
|||||||
private String expandMap(Object object) {
|
private String expandMap(Object object) {
|
||||||
Map<String, Object> paramMap = (Map) object;
|
Map<String, Object> paramMap = (Map) object;
|
||||||
|
|
||||||
return paramMap.keySet().stream()
|
return paramMap.keySet().stream().filter(key -> paramMap.get(key) != null)
|
||||||
.map(key -> ";" + key + "=" + paramMap.get(key).toString())
|
.map(key -> ";" + key + "=" + paramMap.get(key).toString())
|
||||||
.collect(Collectors.joining());
|
.collect(Collectors.joining());
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-37
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2016-2020 the original author or authors.
|
* Copyright 2016-2021 the original author or authors.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -16,37 +16,30 @@
|
|||||||
|
|
||||||
package org.springframework.cloud.openfeign.hateoas;
|
package org.springframework.cloud.openfeign.hateoas;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
|
||||||
import org.springframework.beans.factory.ObjectProvider;
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||||
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||||
import org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration;
|
import org.springframework.boot.autoconfigure.data.rest.RepositoryRestMvcAutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.hateoas.HypermediaAutoConfiguration;
|
|
||||||
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
|
import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration;
|
||||||
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
|
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.hateoas.RepresentationModel;
|
import org.springframework.hateoas.RepresentationModel;
|
||||||
import org.springframework.hateoas.mediatype.MessageResolver;
|
import org.springframework.hateoas.mediatype.hal.HalMediaTypeConfiguration;
|
||||||
import org.springframework.hateoas.mediatype.hal.CurieProvider;
|
|
||||||
import org.springframework.hateoas.mediatype.hal.DefaultCurieProvider;
|
|
||||||
import org.springframework.hateoas.mediatype.hal.HalConfiguration;
|
|
||||||
import org.springframework.hateoas.mediatype.hal.Jackson2HalModule;
|
|
||||||
import org.springframework.hateoas.server.LinkRelationProvider;
|
|
||||||
import org.springframework.hateoas.server.mvc.TypeConstrainedMappingJackson2HttpMessageConverter;
|
import org.springframework.hateoas.server.mvc.TypeConstrainedMappingJackson2HttpMessageConverter;
|
||||||
|
|
||||||
import static org.springframework.hateoas.MediaTypes.HAL_JSON;
|
import static org.springframework.hateoas.MediaTypes.HAL_JSON;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Hector Espert
|
* @author Hector Espert
|
||||||
|
* @author Olga Maciaszek-Sharma
|
||||||
*/
|
*/
|
||||||
@Configuration(proxyBeanMethods = false)
|
@Configuration(proxyBeanMethods = false)
|
||||||
@ConditionalOnWebApplication
|
@ConditionalOnWebApplication
|
||||||
@@ -54,41 +47,19 @@ import static org.springframework.hateoas.MediaTypes.HAL_JSON;
|
|||||||
@AutoConfigureAfter({ JacksonAutoConfiguration.class,
|
@AutoConfigureAfter({ JacksonAutoConfiguration.class,
|
||||||
HttpMessageConvertersAutoConfiguration.class,
|
HttpMessageConvertersAutoConfiguration.class,
|
||||||
RepositoryRestMvcAutoConfiguration.class })
|
RepositoryRestMvcAutoConfiguration.class })
|
||||||
@AutoConfigureBefore(HypermediaAutoConfiguration.class)
|
|
||||||
public class FeignHalAutoConfiguration {
|
public class FeignHalAutoConfiguration {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
@ConditionalOnBean(HalMediaTypeConfiguration.class)
|
||||||
@ConditionalOnMissingBean
|
@ConditionalOnMissingBean
|
||||||
public TypeConstrainedMappingJackson2HttpMessageConverter halJacksonHttpMessageConverter(
|
public TypeConstrainedMappingJackson2HttpMessageConverter halJacksonHttpMessageConverter(
|
||||||
ObjectProvider<ObjectMapper> objectMapper,
|
ObjectProvider<ObjectMapper> objectMapper,
|
||||||
ObjectProvider<HalConfiguration> halConfiguration,
|
HalMediaTypeConfiguration halConfiguration) {
|
||||||
ObjectProvider<MessageResolver> messageResolver,
|
|
||||||
ObjectProvider<CurieProvider> curieProvider,
|
|
||||||
ObjectProvider<LinkRelationProvider> linkRelationProvider) {
|
|
||||||
|
|
||||||
ObjectMapper mapper = objectMapper.getIfAvailable(ObjectMapper::new).copy();
|
ObjectMapper mapper = objectMapper.getIfAvailable(ObjectMapper::new).copy();
|
||||||
mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
|
halConfiguration.configureObjectMapper(mapper);
|
||||||
|
|
||||||
HalConfiguration configuration = halConfiguration
|
|
||||||
.getIfAvailable(HalConfiguration::new);
|
|
||||||
|
|
||||||
CurieProvider curieProviderInstance = curieProvider
|
|
||||||
.getIfAvailable(() -> new DefaultCurieProvider(Collections.emptyMap()));
|
|
||||||
|
|
||||||
Jackson2HalModule.HalHandlerInstantiator halHandlerInstantiator = new Jackson2HalModule.HalHandlerInstantiator(
|
|
||||||
linkRelationProvider.getIfAvailable(), curieProviderInstance,
|
|
||||||
messageResolver.getIfAvailable(), configuration);
|
|
||||||
|
|
||||||
mapper.setHandlerInstantiator(halHandlerInstantiator);
|
|
||||||
|
|
||||||
if (!Jackson2HalModule.isAlreadyRegisteredIn(mapper)) {
|
|
||||||
Jackson2HalModule halModule = new Jackson2HalModule();
|
|
||||||
mapper.registerModule(halModule);
|
|
||||||
}
|
|
||||||
|
|
||||||
TypeConstrainedMappingJackson2HttpMessageConverter converter = new TypeConstrainedMappingJackson2HttpMessageConverter(
|
TypeConstrainedMappingJackson2HttpMessageConverter converter = new TypeConstrainedMappingJackson2HttpMessageConverter(
|
||||||
RepresentationModel.class);
|
RepresentationModel.class);
|
||||||
converter.setSupportedMediaTypes(Arrays.asList(HAL_JSON));
|
converter.setSupportedMediaTypes(Collections.singletonList(HAL_JSON));
|
||||||
converter.setObjectMapper(mapper);
|
converter.setObjectMapper(mapper);
|
||||||
return converter;
|
return converter;
|
||||||
}
|
}
|
||||||
|
|||||||
+50
@@ -0,0 +1,50 @@
|
|||||||
|
/*
|
||||||
|
* 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.loadbalancer;
|
||||||
|
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.net.URI;
|
||||||
|
|
||||||
|
import feign.Response;
|
||||||
|
|
||||||
|
import org.springframework.cloud.client.loadbalancer.RetryableStatusCodeException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link RetryableStatusCodeException} for {@link Response}s.
|
||||||
|
*
|
||||||
|
* @author Ryan Baxter
|
||||||
|
*/
|
||||||
|
public class LoadBalancerResponseStatusCodeException
|
||||||
|
extends RetryableStatusCodeException {
|
||||||
|
|
||||||
|
private final Response response;
|
||||||
|
|
||||||
|
public LoadBalancerResponseStatusCodeException(String serviceId, Response response,
|
||||||
|
byte[] body, URI uri) {
|
||||||
|
super(serviceId, response.status(), response, uri);
|
||||||
|
this.response = Response.builder()
|
||||||
|
.body(new ByteArrayInputStream(body), body.length)
|
||||||
|
.headers(response.headers()).reason(response.reason())
|
||||||
|
.status(response.status()).request(response.request()).build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response getResponse() {
|
||||||
|
return this.response;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+5
-3
@@ -36,7 +36,6 @@ import org.springframework.cloud.client.loadbalancer.LoadBalancedRecoveryCallbac
|
|||||||
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryContext;
|
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryContext;
|
||||||
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryFactory;
|
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryFactory;
|
||||||
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryPolicy;
|
import org.springframework.cloud.client.loadbalancer.LoadBalancedRetryPolicy;
|
||||||
import org.springframework.cloud.client.loadbalancer.RetryableStatusCodeException;
|
|
||||||
import org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient;
|
import org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
@@ -46,6 +45,7 @@ import org.springframework.retry.backoff.BackOffPolicy;
|
|||||||
import org.springframework.retry.backoff.NoBackOffPolicy;
|
import org.springframework.retry.backoff.NoBackOffPolicy;
|
||||||
import org.springframework.retry.policy.NeverRetryPolicy;
|
import org.springframework.retry.policy.NeverRetryPolicy;
|
||||||
import org.springframework.retry.support.RetryTemplate;
|
import org.springframework.retry.support.RetryTemplate;
|
||||||
|
import org.springframework.util.StreamUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link Client} implementation that provides Spring Retry support for requests
|
* A {@link Client} implementation that provides Spring Retry support for requests
|
||||||
@@ -112,9 +112,11 @@ public class RetryableFeignBlockingLoadBalancerClient implements Client {
|
|||||||
LOG.debug(
|
LOG.debug(
|
||||||
String.format("Retrying on status code: %d", responseStatus));
|
String.format("Retrying on status code: %d", responseStatus));
|
||||||
}
|
}
|
||||||
|
byte[] byteArray = response.body() == null ? new byte[] {}
|
||||||
|
: StreamUtils.copyToByteArray(response.body().asInputStream());
|
||||||
response.close();
|
response.close();
|
||||||
throw new RetryableStatusCodeException(serviceId, responseStatus,
|
throw new LoadBalancerResponseStatusCodeException(serviceId, response,
|
||||||
response, URI.create(request.url()));
|
byteArray, URI.create(request.url()));
|
||||||
}
|
}
|
||||||
return response;
|
return response;
|
||||||
}, new LoadBalancedRecoveryCallback<Response, Response>() {
|
}, new LoadBalancedRecoveryCallback<Response, Response>() {
|
||||||
|
|||||||
+24
-9
@@ -24,6 +24,7 @@ import java.nio.charset.Charset;
|
|||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import feign.RequestTemplate;
|
import feign.RequestTemplate;
|
||||||
@@ -48,6 +49,10 @@ import org.springframework.web.multipart.MultipartFile;
|
|||||||
|
|
||||||
import static org.springframework.cloud.openfeign.support.FeignUtils.getHeaders;
|
import static org.springframework.cloud.openfeign.support.FeignUtils.getHeaders;
|
||||||
import static org.springframework.cloud.openfeign.support.FeignUtils.getHttpHeaders;
|
import static org.springframework.cloud.openfeign.support.FeignUtils.getHttpHeaders;
|
||||||
|
import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED;
|
||||||
|
import static org.springframework.http.MediaType.MULTIPART_FORM_DATA;
|
||||||
|
import static org.springframework.http.MediaType.MULTIPART_MIXED;
|
||||||
|
import static org.springframework.http.MediaType.MULTIPART_RELATED;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Spencer Gibb
|
* @author Spencer Gibb
|
||||||
@@ -56,6 +61,7 @@ import static org.springframework.cloud.openfeign.support.FeignUtils.getHttpHead
|
|||||||
* @author Aaron Whiteside
|
* @author Aaron Whiteside
|
||||||
* @author Darren Foong
|
* @author Darren Foong
|
||||||
* @author Olga Maciaszek-Sharma
|
* @author Olga Maciaszek-Sharma
|
||||||
|
* @author Can Bezmen
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
public class SpringEncoder implements Encoder {
|
public class SpringEncoder implements Encoder {
|
||||||
@@ -99,8 +105,8 @@ public class SpringEncoder implements Encoder {
|
|||||||
requestContentType = MediaType.valueOf(type);
|
requestContentType = MediaType.valueOf(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isMultipartType(requestContentType)) {
|
if (isFormRelatedContentType(requestContentType)) {
|
||||||
this.springFormEncoder.encode(requestBody, bodyType, request);
|
springFormEncoder.encode(requestBody, bodyType, request);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -117,7 +123,7 @@ public class SpringEncoder implements Encoder {
|
|||||||
|
|
||||||
private void encodeWithMessageConverter(Object requestBody, Type bodyType,
|
private void encodeWithMessageConverter(Object requestBody, Type bodyType,
|
||||||
RequestTemplate request, MediaType requestContentType) {
|
RequestTemplate request, MediaType requestContentType) {
|
||||||
for (HttpMessageConverter messageConverter : this.messageConverters.getObject()
|
for (HttpMessageConverter messageConverter : messageConverters.getObject()
|
||||||
.getConverters()) {
|
.getConverters()) {
|
||||||
FeignOutputMessage outputMessage;
|
FeignOutputMessage outputMessage;
|
||||||
try {
|
try {
|
||||||
@@ -223,9 +229,18 @@ public class SpringEncoder implements Encoder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isFormRelatedContentType(MediaType requestContentType) {
|
||||||
|
return isMultipartType(requestContentType)
|
||||||
|
|| isFormUrlEncoded(requestContentType);
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isMultipartType(MediaType requestContentType) {
|
private boolean isMultipartType(MediaType requestContentType) {
|
||||||
return Arrays.asList(MediaType.MULTIPART_FORM_DATA, MediaType.MULTIPART_MIXED,
|
return Arrays.asList(MULTIPART_FORM_DATA, MULTIPART_MIXED, MULTIPART_RELATED)
|
||||||
MediaType.MULTIPART_RELATED).contains(requestContentType);
|
.contains(requestContentType);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isFormUrlEncoded(MediaType requestContentType) {
|
||||||
|
return Objects.equals(APPLICATION_FORM_URLENCODED, requestContentType);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean binaryContentType(FeignOutputMessage outputMessage) {
|
private boolean binaryContentType(FeignOutputMessage outputMessage) {
|
||||||
@@ -244,21 +259,21 @@ public class SpringEncoder implements Encoder {
|
|||||||
private final HttpHeaders httpHeaders;
|
private final HttpHeaders httpHeaders;
|
||||||
|
|
||||||
private FeignOutputMessage(RequestTemplate request) {
|
private FeignOutputMessage(RequestTemplate request) {
|
||||||
this.httpHeaders = getHttpHeaders(request.headers());
|
httpHeaders = getHttpHeaders(request.headers());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public OutputStream getBody() throws IOException {
|
public OutputStream getBody() throws IOException {
|
||||||
return this.outputStream;
|
return outputStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public HttpHeaders getHeaders() {
|
public HttpHeaders getHeaders() {
|
||||||
return this.httpHeaders;
|
return httpHeaders;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ByteArrayOutputStream getOutputStream() {
|
public ByteArrayOutputStream getOutputStream() {
|
||||||
return this.outputStream;
|
return outputStream;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-37
@@ -35,6 +35,8 @@ import feign.Feign;
|
|||||||
import feign.MethodMetadata;
|
import feign.MethodMetadata;
|
||||||
import feign.Param;
|
import feign.Param;
|
||||||
import feign.Request;
|
import feign.Request;
|
||||||
|
import org.apache.commons.logging.Log;
|
||||||
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
import org.springframework.cloud.openfeign.AnnotatedParameterProcessor;
|
import org.springframework.cloud.openfeign.AnnotatedParameterProcessor;
|
||||||
import org.springframework.cloud.openfeign.CollectionFormat;
|
import org.springframework.cloud.openfeign.CollectionFormat;
|
||||||
@@ -83,6 +85,8 @@ import static org.springframework.core.annotation.AnnotatedElementUtils.findMerg
|
|||||||
public class SpringMvcContract extends Contract.BaseContract
|
public class SpringMvcContract extends Contract.BaseContract
|
||||||
implements ResourceLoaderAware {
|
implements ResourceLoaderAware {
|
||||||
|
|
||||||
|
private static final Log LOG = LogFactory.getLog(SpringMvcContract.class);
|
||||||
|
|
||||||
private static final String ACCEPT = "Accept";
|
private static final String ACCEPT = "Accept";
|
||||||
|
|
||||||
private static final String CONTENT_TYPE = "Content-Type";
|
private static final String CONTENT_TYPE = "Content-Type";
|
||||||
@@ -181,49 +185,19 @@ public class SpringMvcContract extends Contract.BaseContract
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void processAnnotationOnClass(MethodMetadata data, Class<?> clz) {
|
protected void processAnnotationOnClass(MethodMetadata data, Class<?> clz) {
|
||||||
if (clz.getInterfaces().length == 0) {
|
RequestMapping classAnnotation = findMergedAnnotation(clz, RequestMapping.class);
|
||||||
RequestMapping classAnnotation = findMergedAnnotation(clz,
|
if (classAnnotation != null) {
|
||||||
RequestMapping.class);
|
LOG.error("Cannot process class: " + clz.getName()
|
||||||
if (classAnnotation != null) {
|
+ ". @RequestMapping annotation is not allowed on @FeignClient interfaces.");
|
||||||
// Prepend path from class annotation if specified
|
throw new IllegalArgumentException(
|
||||||
if (classAnnotation.value().length > 0) {
|
"@RequestMapping annotation not allowed on @FeignClient interfaces");
|
||||||
String pathValue = emptyToNull(classAnnotation.value()[0]);
|
|
||||||
pathValue = resolve(pathValue);
|
|
||||||
if (!pathValue.startsWith("/")) {
|
|
||||||
pathValue = "/" + pathValue;
|
|
||||||
}
|
|
||||||
data.template().uri(pathValue);
|
|
||||||
if (data.template().decodeSlash() != decodeSlash) {
|
|
||||||
data.template().decodeSlash(decodeSlash);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MethodMetadata parseAndValidateMetadata(Class<?> targetType, Method method) {
|
public MethodMetadata parseAndValidateMetadata(Class<?> targetType, Method method) {
|
||||||
processedMethods.put(Feign.configKey(targetType, method), method);
|
processedMethods.put(Feign.configKey(targetType, method), method);
|
||||||
MethodMetadata md = super.parseAndValidateMetadata(targetType, method);
|
return super.parseAndValidateMetadata(targetType, method);
|
||||||
|
|
||||||
RequestMapping classAnnotation = findMergedAnnotation(targetType,
|
|
||||||
RequestMapping.class);
|
|
||||||
if (classAnnotation != null) {
|
|
||||||
// produces - use from class annotation only if method has not specified this
|
|
||||||
if (!md.template().headers().containsKey(ACCEPT)) {
|
|
||||||
parseProduces(md, method, classAnnotation);
|
|
||||||
}
|
|
||||||
|
|
||||||
// consumes -- use from class annotation only if method has not specified this
|
|
||||||
if (!md.template().headers().containsKey(CONTENT_TYPE)) {
|
|
||||||
parseConsumes(md, method, classAnnotation);
|
|
||||||
}
|
|
||||||
|
|
||||||
// headers -- class annotation is inherited to methods, always write these if
|
|
||||||
// present
|
|
||||||
parseHeaders(md, method, classAnnotation);
|
|
||||||
}
|
|
||||||
return md;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
+15
-11
@@ -16,7 +16,7 @@
|
|||||||
|
|
||||||
package org.springframework.cloud.openfeign.hateoas;
|
package org.springframework.cloud.openfeign.hateoas;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Collections;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@@ -26,9 +26,11 @@ import org.mockito.Mock;
|
|||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
import org.springframework.beans.factory.ObjectProvider;
|
import org.springframework.beans.factory.ObjectProvider;
|
||||||
|
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||||
import org.springframework.hateoas.mediatype.MessageResolver;
|
import org.springframework.hateoas.mediatype.MessageResolver;
|
||||||
import org.springframework.hateoas.mediatype.hal.CurieProvider;
|
import org.springframework.hateoas.mediatype.hal.CurieProvider;
|
||||||
import org.springframework.hateoas.mediatype.hal.HalConfiguration;
|
import org.springframework.hateoas.mediatype.hal.HalConfiguration;
|
||||||
|
import org.springframework.hateoas.mediatype.hal.HalMediaTypeConfiguration;
|
||||||
import org.springframework.hateoas.mediatype.hal.Jackson2HalModule;
|
import org.springframework.hateoas.mediatype.hal.Jackson2HalModule;
|
||||||
import org.springframework.hateoas.server.LinkRelationProvider;
|
import org.springframework.hateoas.server.LinkRelationProvider;
|
||||||
import org.springframework.hateoas.server.mvc.TypeConstrainedMappingJackson2HttpMessageConverter;
|
import org.springframework.hateoas.server.mvc.TypeConstrainedMappingJackson2HttpMessageConverter;
|
||||||
@@ -45,20 +47,20 @@ import static org.springframework.hateoas.MediaTypes.HAL_JSON;
|
|||||||
@RunWith(MockitoJUnitRunner.class)
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
public class FeignHalAutoConfigurationTests {
|
public class FeignHalAutoConfigurationTests {
|
||||||
|
|
||||||
@Mock
|
|
||||||
private ObjectProvider<ObjectMapper> objectMapper;
|
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private ObjectProvider<HalConfiguration> halConfiguration;
|
private ObjectProvider<HalConfiguration> halConfiguration;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private ObjectProvider<LinkRelationProvider> relProvider;
|
private ObjectProvider<ObjectMapper> objectMapper;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private LinkRelationProvider relProvider;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private ObjectProvider<CurieProvider> curieProvider;
|
private ObjectProvider<CurieProvider> curieProvider;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private ObjectProvider<MessageResolver> messageResolver;
|
private MessageResolver messageResolver;
|
||||||
|
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
private FeignHalAutoConfiguration feignHalAutoConfiguration;
|
private FeignHalAutoConfiguration feignHalAutoConfiguration;
|
||||||
@@ -70,17 +72,19 @@ public class FeignHalAutoConfigurationTests {
|
|||||||
|
|
||||||
when(halConfiguration.getIfAvailable(any()))
|
when(halConfiguration.getIfAvailable(any()))
|
||||||
.thenReturn(mock(HalConfiguration.class));
|
.thenReturn(mock(HalConfiguration.class));
|
||||||
when(relProvider.getIfAvailable()).thenReturn(mock(LinkRelationProvider.class));
|
|
||||||
when(curieProvider.getIfAvailable(any())).thenReturn(mock(CurieProvider.class));
|
when(curieProvider.getIfAvailable(any())).thenReturn(mock(CurieProvider.class));
|
||||||
when(messageResolver.getIfAvailable()).thenReturn(mock(MessageResolver.class));
|
|
||||||
|
HalMediaTypeConfiguration halMediaTypeConfiguration = new HalMediaTypeConfiguration(
|
||||||
|
relProvider, curieProvider, halConfiguration, messageResolver,
|
||||||
|
new DefaultListableBeanFactory());
|
||||||
|
|
||||||
TypeConstrainedMappingJackson2HttpMessageConverter converter = feignHalAutoConfiguration
|
TypeConstrainedMappingJackson2HttpMessageConverter converter = feignHalAutoConfiguration
|
||||||
.halJacksonHttpMessageConverter(objectMapper, halConfiguration,
|
.halJacksonHttpMessageConverter(objectMapper, halMediaTypeConfiguration);
|
||||||
messageResolver, curieProvider, relProvider);
|
|
||||||
|
|
||||||
assertThat(converter).isNotNull();
|
assertThat(converter).isNotNull();
|
||||||
assertThat(converter.getObjectMapper()).isNotNull();
|
assertThat(converter.getObjectMapper()).isNotNull();
|
||||||
assertThat(converter.getSupportedMediaTypes()).isEqualTo(Arrays.asList(HAL_JSON));
|
assertThat(converter.getSupportedMediaTypes())
|
||||||
|
.isEqualTo(Collections.singletonList(HAL_JSON));
|
||||||
|
|
||||||
assertThat(Jackson2HalModule.isAlreadyRegisteredIn(converter.getObjectMapper()))
|
assertThat(Jackson2HalModule.isAlreadyRegisteredIn(converter.getObjectMapper()))
|
||||||
.isTrue();
|
.isTrue();
|
||||||
|
|||||||
+1
-1
@@ -54,7 +54,7 @@ import static org.mockito.Mockito.when;
|
|||||||
* {@link FeignBlockingLoadBalancerClient} and its delegates.
|
* {@link FeignBlockingLoadBalancerClient} and its delegates.
|
||||||
*
|
*
|
||||||
* @see <a href=
|
* @see <a href=
|
||||||
* "https://github.com/spring-cloud/spring-cloud-commons/blob/master/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/blocking/client/BlockingLoadBalancerClientTests.java">BlockingLoadBalancerClientTests</a>
|
* "https://github.com/spring-cloud/spring-cloud-commons/blob/main/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/blocking/client/BlockingLoadBalancerClientTests.java">BlockingLoadBalancerClientTests</a>
|
||||||
* @author Olga Maciaszek-Sharma
|
* @author Olga Maciaszek-Sharma
|
||||||
*/
|
*/
|
||||||
@ExtendWith(MockitoExtension.class)
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
|||||||
+35
-1
@@ -16,7 +16,10 @@
|
|||||||
|
|
||||||
package org.springframework.cloud.openfeign.loadbalancer;
|
package org.springframework.cloud.openfeign.loadbalancer;
|
||||||
|
|
||||||
|
import java.io.BufferedInputStream;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -27,6 +30,7 @@ import java.util.Map;
|
|||||||
import feign.Client;
|
import feign.Client;
|
||||||
import feign.Request;
|
import feign.Request;
|
||||||
import feign.Response;
|
import feign.Response;
|
||||||
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
@@ -58,7 +62,7 @@ import static org.mockito.Mockito.when;
|
|||||||
* {@link RetryableFeignBlockingLoadBalancerClient} and its delegates.
|
* {@link RetryableFeignBlockingLoadBalancerClient} and its delegates.
|
||||||
*
|
*
|
||||||
* @see <a href=
|
* @see <a href=
|
||||||
* "https://github.com/spring-cloud/spring-cloud-commons/blob/master/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/blocking/client/BlockingLoadBalancerClientTests.java">BlockingLoadBalancerClientTests</a>
|
* "https://github.com/spring-cloud/spring-cloud-commons/blob/main/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/blocking/client/BlockingLoadBalancerClientTests.java">BlockingLoadBalancerClientTests</a>
|
||||||
* @author Olga Maciaszek-Sharma
|
* @author Olga Maciaszek-Sharma
|
||||||
*/
|
*/
|
||||||
@ExtendWith(MockitoExtension.class)
|
@ExtendWith(MockitoExtension.class)
|
||||||
@@ -113,6 +117,15 @@ class RetryableFeignBlockingLoadBalancerClientTests {
|
|||||||
return Response.builder().request(testRequest()).status(status).build();
|
return Response.builder().request(testRequest()).status(status).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Response testResponse(int status, String body) {
|
||||||
|
// ByteArrayInputStream ignores close() and must be wrapped
|
||||||
|
InputStream reallyCloseable = new BufferedInputStream(
|
||||||
|
new ByteArrayInputStream(body.getBytes(StandardCharsets.UTF_8)));
|
||||||
|
return Response.builder().request(testRequest()).status(status)
|
||||||
|
.body(reallyCloseable, null).build();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldExecuteOriginalRequestIfInstanceNotFound() throws IOException {
|
void shouldExecuteOriginalRequestIfInstanceNotFound() throws IOException {
|
||||||
Request request = testRequest();
|
Request request = testRequest();
|
||||||
@@ -148,6 +161,27 @@ class RetryableFeignBlockingLoadBalancerClientTests {
|
|||||||
verify(delegate, times(2)).execute(any(), any());
|
verify(delegate, times(2)).execute(any(), any());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldExposeResponseBodyOnRetry() throws IOException {
|
||||||
|
properties.getRetryableStatusCodes().add(503);
|
||||||
|
Request request = testRequest();
|
||||||
|
when(delegate.execute(any(), any())).thenReturn(testResponse(503, "foo"),
|
||||||
|
testResponse(503, "foo"));
|
||||||
|
when(retryFactory.createRetryPolicy(any(), eq(loadBalancerClient)))
|
||||||
|
.thenReturn(new BlockingLoadBalancedRetryPolicy("test",
|
||||||
|
loadBalancerClient, properties));
|
||||||
|
when(loadBalancerClient.reconstructURI(serviceInstance,
|
||||||
|
URI.create("http://test/path")))
|
||||||
|
.thenReturn(URI.create("http://testhost:80/path"));
|
||||||
|
|
||||||
|
Response response = feignBlockingLoadBalancerClient.execute(request,
|
||||||
|
new Request.Options());
|
||||||
|
|
||||||
|
String bodyContent = IOUtils
|
||||||
|
.toString(response.body().asReader(StandardCharsets.UTF_8));
|
||||||
|
assertThat(bodyContent).isEqualTo("foo");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void shouldPassCorrectRequestToDelegate() throws IOException {
|
void shouldPassCorrectRequestToDelegate() throws IOException {
|
||||||
Request request = testRequest();
|
Request request = testRequest();
|
||||||
|
|||||||
+14
@@ -60,6 +60,7 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||||||
import static org.springframework.http.HttpHeaders.ACCEPT;
|
import static org.springframework.http.HttpHeaders.ACCEPT;
|
||||||
import static org.springframework.http.HttpHeaders.CONTENT_LENGTH;
|
import static org.springframework.http.HttpHeaders.CONTENT_LENGTH;
|
||||||
import static org.springframework.http.HttpHeaders.CONTENT_TYPE;
|
import static org.springframework.http.HttpHeaders.CONTENT_TYPE;
|
||||||
|
import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE;
|
||||||
import static org.springframework.http.MediaType.APPLICATION_OCTET_STREAM_VALUE;
|
import static org.springframework.http.MediaType.APPLICATION_OCTET_STREAM_VALUE;
|
||||||
import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE;
|
import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE;
|
||||||
import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE;
|
import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE;
|
||||||
@@ -68,6 +69,7 @@ import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE;
|
|||||||
* @author Spencer Gibb
|
* @author Spencer Gibb
|
||||||
* @author Olga Maciaszek-Sharma
|
* @author Olga Maciaszek-Sharma
|
||||||
* @author Ahmad Mozafarnia
|
* @author Ahmad Mozafarnia
|
||||||
|
* @author Can Bezmen
|
||||||
*/
|
*/
|
||||||
@RunWith(SpringJUnit4ClassRunner.class)
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
@SpringBootTest(classes = SpringEncoderTests.Application.class,
|
@SpringBootTest(classes = SpringEncoderTests.Application.class,
|
||||||
@@ -192,6 +194,18 @@ public class SpringEncoderTests {
|
|||||||
.as("Body content cannot be decoded").contains("hi");
|
.as("Body content cannot be decoded").contains("hi");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFromURLEncodedValue() {
|
||||||
|
Encoder encoder = context.getInstance("formUrlEncoded", Encoder.class);
|
||||||
|
assertThat(encoder).isNotNull();
|
||||||
|
RequestTemplate request = new RequestTemplate();
|
||||||
|
request.header(CONTENT_TYPE, APPLICATION_FORM_URLENCODED_VALUE);
|
||||||
|
String body = "test";
|
||||||
|
encoder.encode(body, String.class, request);
|
||||||
|
assertThat(new String(request.requestBody().asBytes()))
|
||||||
|
.as("Body content cannot be decoded").contains(body);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoCharsetForBinaryFiles() {
|
public void testNoCharsetForBinaryFiles() {
|
||||||
Encoder encoder = context.getInstance("test", Encoder.class);
|
Encoder encoder = context.getInstance("test", Encoder.class);
|
||||||
|
|||||||
+21
-59
@@ -62,6 +62,7 @@ import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.ANY;
|
|||||||
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE;
|
import static com.fasterxml.jackson.annotation.JsonAutoDetect.Visibility.NONE;
|
||||||
import static feign.CollectionFormat.SSV;
|
import static feign.CollectionFormat.SSV;
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||||
import static org.junit.Assume.assumeTrue;
|
import static org.junit.Assume.assumeTrue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -182,18 +183,12 @@ public class SpringMvcContractTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProcessAnnotations_Class_AnnotationsGetSpecificTest()
|
public void testProcessAnnotations_Class_Annotations_RequestMapping() {
|
||||||
throws Exception {
|
assertThatIllegalArgumentException().isThrownBy(() -> {
|
||||||
Method method = TestTemplate_Class_Annotations.class
|
Method method = TestTemplate_Class_RequestMapping.class
|
||||||
.getDeclaredMethod("getSpecificTest", String.class, String.class);
|
.getDeclaredMethod("getSpecificTest", String.class, String.class);
|
||||||
MethodMetadata data = contract
|
contract.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||||
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
});
|
||||||
|
|
||||||
assertThat(data.template().url()).isEqualTo("/prepend/{classId}/test/{testId}");
|
|
||||||
assertThat(data.template().method()).isEqualTo("GET");
|
|
||||||
|
|
||||||
assertThat(data.indexToName().get(0).iterator().next()).isEqualTo("classId");
|
|
||||||
assertThat(data.indexToName().get(1).iterator().next()).isEqualTo("testId");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -203,7 +198,7 @@ public class SpringMvcContractTests {
|
|||||||
MethodMetadata data = contract
|
MethodMetadata data = contract
|
||||||
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||||
|
|
||||||
assertThat(data.template().url()).isEqualTo("/prepend/{classId}");
|
assertThat(data.template().url()).isEqualTo("/");
|
||||||
assertThat(data.template().method()).isEqualTo("GET");
|
assertThat(data.template().method()).isEqualTo("GET");
|
||||||
|
|
||||||
assertThat(data.indexToName().get(0).iterator().next()).isEqualTo("classId");
|
assertThat(data.indexToName().get(0).iterator().next()).isEqualTo("classId");
|
||||||
@@ -211,22 +206,6 @@ public class SpringMvcContractTests {
|
|||||||
assertThat(data.template().decodeSlash()).isTrue();
|
assertThat(data.template().decodeSlash()).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testProcessAnnotations_Class_AnnotationsGetAllTests_EncodeSlash()
|
|
||||||
throws Exception {
|
|
||||||
contract = new SpringMvcContract(Collections.emptyList(), getConversionService(),
|
|
||||||
false);
|
|
||||||
|
|
||||||
Method method = TestTemplate_Class_Annotations.class
|
|
||||||
.getDeclaredMethod("getAllTests", String.class);
|
|
||||||
MethodMetadata data = contract
|
|
||||||
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
|
||||||
|
|
||||||
assertThat(data.template().url()).isEqualTo("/prepend/{classId}");
|
|
||||||
|
|
||||||
assertThat(data.template().decodeSlash()).isFalse();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProcessAnnotations_ExtendedInterface() throws Exception {
|
public void testProcessAnnotations_ExtendedInterface() throws Exception {
|
||||||
Method extendedMethod = TestTemplate_Extended.class.getMethod("getAllTests",
|
Method extendedMethod = TestTemplate_Extended.class.getMethod("getAllTests",
|
||||||
@@ -249,27 +228,6 @@ public class SpringMvcContractTests {
|
|||||||
assertThat(data.template().decodeSlash()).isTrue();
|
assertThat(data.template().decodeSlash()).isTrue();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testProcessAnnotations_ExtendedInterface_EncodeSlash() throws Exception {
|
|
||||||
contract = new SpringMvcContract(Collections.emptyList(), getConversionService(),
|
|
||||||
false);
|
|
||||||
|
|
||||||
Method extendedMethod = TestTemplate_Extended.class.getMethod("getAllTests",
|
|
||||||
String.class);
|
|
||||||
MethodMetadata extendedData = contract.parseAndValidateMetadata(
|
|
||||||
extendedMethod.getDeclaringClass(), extendedMethod);
|
|
||||||
|
|
||||||
Method method = TestTemplate_Class_Annotations.class
|
|
||||||
.getDeclaredMethod("getAllTests", String.class);
|
|
||||||
MethodMetadata data = contract
|
|
||||||
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
|
||||||
|
|
||||||
assertThat(data.template().url()).isEqualTo(extendedData.template().url());
|
|
||||||
assertThat(data.template().method()).isEqualTo(extendedData.template().method());
|
|
||||||
|
|
||||||
assertThat(data.template().decodeSlash()).isFalse();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProcessAnnotations_SimplePost() throws Exception {
|
public void testProcessAnnotations_SimplePost() throws Exception {
|
||||||
Method method = TestTemplate_Simple.class.getDeclaredMethod("postTest",
|
Method method = TestTemplate_Simple.class.getDeclaredMethod("postTest",
|
||||||
@@ -305,8 +263,7 @@ public class SpringMvcContractTests {
|
|||||||
MethodMetadata data = contract
|
MethodMetadata data = contract
|
||||||
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||||
|
|
||||||
assertThat(data.template().url())
|
assertThat(data.template().url()).isEqualTo("/test/{id}?amount=" + "{amount}");
|
||||||
.isEqualTo("/advanced/test/{id}?amount=" + "{amount}");
|
|
||||||
assertThat(data.template().method()).isEqualTo("PUT");
|
assertThat(data.template().method()).isEqualTo("PUT");
|
||||||
assertThat(data.template().headers().get("Accept").iterator().next())
|
assertThat(data.template().headers().get("Accept").iterator().next())
|
||||||
.isEqualTo(MediaType.APPLICATION_JSON_VALUE);
|
.isEqualTo(MediaType.APPLICATION_JSON_VALUE);
|
||||||
@@ -341,8 +298,7 @@ public class SpringMvcContractTests {
|
|||||||
MethodMetadata data = contract
|
MethodMetadata data = contract
|
||||||
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||||
|
|
||||||
assertThat(data.template().url())
|
assertThat(data.template().url()).isEqualTo("/test/{id}?amount=" + "{amount}");
|
||||||
.isEqualTo("/advanced/test/{id}?amount=" + "{amount}");
|
|
||||||
assertThat(data.template().method()).isEqualTo("PUT");
|
assertThat(data.template().method()).isEqualTo("PUT");
|
||||||
assertThat(data.template().headers().get("Accept").iterator().next())
|
assertThat(data.template().headers().get("Accept").iterator().next())
|
||||||
.isEqualTo(MediaType.APPLICATION_JSON_VALUE);
|
.isEqualTo(MediaType.APPLICATION_JSON_VALUE);
|
||||||
@@ -366,8 +322,7 @@ public class SpringMvcContractTests {
|
|||||||
MethodMetadata data = contract
|
MethodMetadata data = contract
|
||||||
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||||
|
|
||||||
assertThat(data.template().url())
|
assertThat(data.template().url()).isEqualTo("/test2?amount=" + "{amount}");
|
||||||
.isEqualTo("/advanced/test2?amount=" + "{amount}");
|
|
||||||
assertThat(data.template().method()).isEqualTo("PUT");
|
assertThat(data.template().method()).isEqualTo("PUT");
|
||||||
assertThat(data.template().headers().get("Accept").iterator().next())
|
assertThat(data.template().headers().get("Accept").iterator().next())
|
||||||
.isEqualTo(MediaType.APPLICATION_JSON_VALUE);
|
.isEqualTo(MediaType.APPLICATION_JSON_VALUE);
|
||||||
@@ -429,7 +384,7 @@ public class SpringMvcContractTests {
|
|||||||
MethodMetadata data = contract
|
MethodMetadata data = contract
|
||||||
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||||
|
|
||||||
assertThat(data.template().url()).isEqualTo("/advanced");
|
assertThat(data.template().url()).isEqualTo("/");
|
||||||
assertThat(data.template().method()).isEqualTo("GET");
|
assertThat(data.template().method()).isEqualTo("GET");
|
||||||
assertThat(data.template().headers().get("Accept").iterator().next())
|
assertThat(data.template().headers().get("Accept").iterator().next())
|
||||||
.isEqualTo(MediaType.APPLICATION_JSON_VALUE);
|
.isEqualTo(MediaType.APPLICATION_JSON_VALUE);
|
||||||
@@ -539,7 +494,7 @@ public class SpringMvcContractTests {
|
|||||||
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||||
|
|
||||||
assertThat(data.template().url())
|
assertThat(data.template().url())
|
||||||
.isEqualTo("/advanced/testfallback/{id}?amount=" + "{amount}");
|
.isEqualTo("/testfallback/{id}?amount=" + "{amount}");
|
||||||
assertThat(data.template().method()).isEqualTo("PUT");
|
assertThat(data.template().method()).isEqualTo("PUT");
|
||||||
assertThat(data.template().headers().get("Accept").iterator().next())
|
assertThat(data.template().headers().get("Accept").iterator().next())
|
||||||
.isEqualTo(MediaType.APPLICATION_JSON_VALUE);
|
.isEqualTo(MediaType.APPLICATION_JSON_VALUE);
|
||||||
@@ -708,6 +663,14 @@ public class SpringMvcContractTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping("/prepend/{classId}")
|
@RequestMapping("/prepend/{classId}")
|
||||||
|
public interface TestTemplate_Class_RequestMapping {
|
||||||
|
|
||||||
|
@RequestMapping(value = "/test/{testId}", method = RequestMethod.GET)
|
||||||
|
TestObject getSpecificTest(@PathVariable("classId") String classId,
|
||||||
|
@PathVariable("testId") String testId);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
public interface TestTemplate_Class_Annotations {
|
public interface TestTemplate_Class_Annotations {
|
||||||
|
|
||||||
@RequestMapping(value = "/test/{testId}", method = RequestMethod.GET)
|
@RequestMapping(value = "/test/{testId}", method = RequestMethod.GET)
|
||||||
@@ -812,7 +775,6 @@ public class SpringMvcContractTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@JsonAutoDetect
|
@JsonAutoDetect
|
||||||
@RequestMapping("/advanced")
|
|
||||||
public interface TestTemplate_Advanced {
|
public interface TestTemplate_Advanced {
|
||||||
|
|
||||||
@CollectionFormat(SSV)
|
@CollectionFormat(SSV)
|
||||||
|
|||||||
+87
-79
@@ -17,7 +17,6 @@
|
|||||||
package org.springframework.cloud.openfeign.valid;
|
package org.springframework.cloud.openfeign.valid;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationHandler;
|
import java.lang.reflect.InvocationHandler;
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.lang.reflect.Proxy;
|
import java.lang.reflect.Proxy;
|
||||||
import java.text.ParseException;
|
import java.text.ParseException;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
@@ -49,7 +48,6 @@ import feign.Feign;
|
|||||||
import feign.Logger;
|
import feign.Logger;
|
||||||
import feign.RequestInterceptor;
|
import feign.RequestInterceptor;
|
||||||
import feign.RequestTemplate;
|
import feign.RequestTemplate;
|
||||||
import feign.Target;
|
|
||||||
import feign.codec.EncodeException;
|
import feign.codec.EncodeException;
|
||||||
import feign.hystrix.FallbackFactory;
|
import feign.hystrix.FallbackFactory;
|
||||||
import feign.hystrix.SetterFactory;
|
import feign.hystrix.SetterFactory;
|
||||||
@@ -91,6 +89,7 @@ import org.springframework.http.ResponseEntity;
|
|||||||
import org.springframework.mock.web.MockMultipartFile;
|
import org.springframework.mock.web.MockMultipartFile;
|
||||||
import org.springframework.test.annotation.DirtiesContext;
|
import org.springframework.test.annotation.DirtiesContext;
|
||||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestHeader;
|
import org.springframework.web.bind.annotation.RequestHeader;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
@@ -102,6 +101,7 @@ import org.springframework.web.multipart.MultipartFile;
|
|||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.hamcrest.core.IsInstanceOf.instanceOf;
|
import static org.hamcrest.core.IsInstanceOf.instanceOf;
|
||||||
|
import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Spencer Gibb
|
* @author Spencer Gibb
|
||||||
@@ -110,6 +110,7 @@ import static org.hamcrest.core.IsInstanceOf.instanceOf;
|
|||||||
* @author Halvdan Hoem Grelland
|
* @author Halvdan Hoem Grelland
|
||||||
* @author Aaron Whiteside
|
* @author Aaron Whiteside
|
||||||
* @author Darren Foong
|
* @author Darren Foong
|
||||||
|
* @author Can Bezmen
|
||||||
*/
|
*/
|
||||||
@RunWith(SpringJUnit4ClassRunner.class)
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
@SpringBootTest(classes = FeignClientTests.Application.class,
|
@SpringBootTest(classes = FeignClientTests.Application.class,
|
||||||
@@ -178,23 +179,23 @@ public class FeignClientTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testClient() {
|
public void testClient() {
|
||||||
assertThat(this.testClient).as("testClient was null").isNotNull();
|
assertThat(testClient).as("testClient was null").isNotNull();
|
||||||
assertThat(Proxy.isProxyClass(this.testClient.getClass()))
|
assertThat(Proxy.isProxyClass(testClient.getClass()))
|
||||||
.as("testClient is not a java Proxy").isTrue();
|
.as("testClient is not a java Proxy").isTrue();
|
||||||
InvocationHandler invocationHandler = Proxy.getInvocationHandler(this.testClient);
|
InvocationHandler invocationHandler = Proxy.getInvocationHandler(testClient);
|
||||||
assertThat(invocationHandler).as("invocationHandler was null").isNotNull();
|
assertThat(invocationHandler).as("invocationHandler was null").isNotNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRequestMappingClassLevelPropertyReplacement() {
|
public void testRequestMappingClassLevelPropertyReplacement() {
|
||||||
Hello hello = this.testClient.getHelloUsingPropertyPlaceHolder();
|
Hello hello = testClient.getHelloUsingPropertyPlaceHolder();
|
||||||
assertThat(hello).as("hello was null").isNotNull();
|
assertThat(hello).as("hello was null").isNotNull();
|
||||||
assertThat(hello).as("first hello didn't match").isEqualTo(new Hello(OI_TERRA_2));
|
assertThat(hello).as("first hello didn't match").isEqualTo(new Hello(OI_TERRA_2));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSimpleType() {
|
public void testSimpleType() {
|
||||||
Hello hello = this.testClient.getHello();
|
Hello hello = testClient.getHello();
|
||||||
assertThat(hello).as("hello was null").isNotNull();
|
assertThat(hello).as("hello was null").isNotNull();
|
||||||
assertThat(hello).as("first hello didn't match")
|
assertThat(hello).as("first hello didn't match")
|
||||||
.isEqualTo(new Hello(HELLO_WORLD_1));
|
.isEqualTo(new Hello(HELLO_WORLD_1));
|
||||||
@@ -202,20 +203,20 @@ public class FeignClientTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOptional() {
|
public void testOptional() {
|
||||||
Optional<Hello> hello = this.testClient.getOptionalHello();
|
Optional<Hello> hello = testClient.getOptionalHello();
|
||||||
assertThat(hello).isNotNull().isPresent().contains(new Hello(HELLO_WORLD_1));
|
assertThat(hello).isNotNull().isPresent().contains(new Hello(HELLO_WORLD_1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGenericType() {
|
public void testGenericType() {
|
||||||
List<Hello> hellos = this.testClient.getHellos();
|
List<Hello> hellos = testClient.getHellos();
|
||||||
assertThat(hellos).as("hellos was null").isNotNull();
|
assertThat(hellos).as("hellos was null").isNotNull();
|
||||||
assertThat(getHelloList()).as("hellos didn't match").isEqualTo(hellos);
|
assertThat(getHelloList()).as("hellos didn't match").isEqualTo(hellos);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRequestInterceptors() {
|
public void testRequestInterceptors() {
|
||||||
List<String> headers = this.testClient.getHelloHeaders();
|
List<String> headers = testClient.getHelloHeaders();
|
||||||
assertThat(headers).as("headers was null").isNotNull();
|
assertThat(headers).as("headers was null").isNotNull();
|
||||||
assertThat(headers.contains("myheader1value"))
|
assertThat(headers.contains("myheader1value"))
|
||||||
.as("headers didn't contain myheader1value").isTrue();
|
.as("headers didn't contain myheader1value").isTrue();
|
||||||
@@ -225,24 +226,23 @@ public class FeignClientTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHeaderPlaceholders() {
|
public void testHeaderPlaceholders() {
|
||||||
String header = this.testClient.getHelloHeadersPlaceholders();
|
String header = testClient.getHelloHeadersPlaceholders();
|
||||||
assertThat(header).as("header was null").isNotNull();
|
assertThat(header).as("header was null").isNotNull();
|
||||||
assertThat(header).as("header was wrong").isEqualTo("myPlaceholderHeaderValue");
|
assertThat(header).as("header was wrong").isEqualTo("myPlaceholderHeaderValue");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFeignClientType() throws IllegalAccessException {
|
public void testFeignClientType() {
|
||||||
assertThat(this.feignClient).isInstanceOf(LoadBalancerFeignClient.class);
|
assertThat(feignClient).isInstanceOf(LoadBalancerFeignClient.class);
|
||||||
LoadBalancerFeignClient client = (LoadBalancerFeignClient) this.feignClient;
|
LoadBalancerFeignClient client = (LoadBalancerFeignClient) feignClient;
|
||||||
Client delegate = client.getDelegate();
|
Client delegate = client.getDelegate();
|
||||||
assertThat(delegate).isInstanceOf(Client.Default.class);
|
assertThat(delegate).isInstanceOf(Client.Default.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testServiceId() {
|
public void testServiceId() {
|
||||||
assertThat(this.testClientServiceId).as("testClientServiceId was null")
|
assertThat(testClientServiceId).as("testClientServiceId was null").isNotNull();
|
||||||
.isNotNull();
|
final Hello hello = testClientServiceId.getHello();
|
||||||
final Hello hello = this.testClientServiceId.getHello();
|
|
||||||
assertThat(hello).as("The hello response was null").isNotNull();
|
assertThat(hello).as("The hello response was null").isNotNull();
|
||||||
assertThat(hello).as("first hello didn't match")
|
assertThat(hello).as("first hello didn't match")
|
||||||
.isEqualTo(new Hello(HELLO_WORLD_1));
|
.isEqualTo(new Hello(HELLO_WORLD_1));
|
||||||
@@ -251,7 +251,7 @@ public class FeignClientTests {
|
|||||||
@Test
|
@Test
|
||||||
public void testParams() {
|
public void testParams() {
|
||||||
List<String> list = Arrays.asList("a", "1", "test");
|
List<String> list = Arrays.asList("a", "1", "test");
|
||||||
List<String> params = this.testClient.getParams(list);
|
List<String> params = testClient.getParams(list);
|
||||||
assertThat(params).as("params was null").isNotNull();
|
assertThat(params).as("params was null").isNotNull();
|
||||||
assertThat(params.size()).as("params size was wrong").isEqualTo(list.size());
|
assertThat(params.size()).as("params size was wrong").isEqualTo(list.size());
|
||||||
}
|
}
|
||||||
@@ -260,14 +260,14 @@ public class FeignClientTests {
|
|||||||
public void testFormattedParams() {
|
public void testFormattedParams() {
|
||||||
List<LocalDate> list = Arrays.asList(LocalDate.of(2001, 1, 1),
|
List<LocalDate> list = Arrays.asList(LocalDate.of(2001, 1, 1),
|
||||||
LocalDate.of(2018, 6, 10));
|
LocalDate.of(2018, 6, 10));
|
||||||
List<LocalDate> params = this.testClient.getFormattedParams(list);
|
List<LocalDate> params = testClient.getFormattedParams(list);
|
||||||
assertThat(params).as("params was null").isNotNull();
|
assertThat(params).as("params was null").isNotNull();
|
||||||
assertThat(params).as("params not converted correctly").isEqualTo(list);
|
assertThat(params).as("params not converted correctly").isEqualTo(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHystrixCommand() throws NoSuchMethodException {
|
public void testHystrixCommand() throws NoSuchMethodException {
|
||||||
HystrixCommand<List<Hello>> command = this.testClient.getHellosHystrix();
|
HystrixCommand<List<Hello>> command = testClient.getHellosHystrix();
|
||||||
assertThat(command).as("command was null").isNotNull();
|
assertThat(command).as("command was null").isNotNull();
|
||||||
assertThat(command.getCommandGroup().name()).as(
|
assertThat(command.getCommandGroup().name()).as(
|
||||||
"Hystrix command group name should match the name of the feign client")
|
"Hystrix command group name should match the name of the feign client")
|
||||||
@@ -284,7 +284,7 @@ public class FeignClientTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSingle() {
|
public void testSingle() {
|
||||||
Single<Hello> single = this.testClient.getHelloSingle();
|
Single<Hello> single = testClient.getHelloSingle();
|
||||||
assertThat(single).as("single was null").isNotNull();
|
assertThat(single).as("single was null").isNotNull();
|
||||||
Hello hello = single.toBlocking().value();
|
Hello hello = single.toBlocking().value();
|
||||||
assertThat(hello).as("hello was null").isNotNull();
|
assertThat(hello).as("hello was null").isNotNull();
|
||||||
@@ -294,7 +294,7 @@ public class FeignClientTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNoContentResponse() {
|
public void testNoContentResponse() {
|
||||||
ResponseEntity<Void> response = this.testClient.noContent();
|
ResponseEntity<Void> response = testClient.noContent();
|
||||||
assertThat(response).as("response was null").isNotNull();
|
assertThat(response).as("response was null").isNotNull();
|
||||||
assertThat(response.getStatusCode()).as("status code was wrong")
|
assertThat(response.getStatusCode()).as("status code was wrong")
|
||||||
.isEqualTo(HttpStatus.NO_CONTENT);
|
.isEqualTo(HttpStatus.NO_CONTENT);
|
||||||
@@ -302,7 +302,7 @@ public class FeignClientTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHeadResponse() {
|
public void testHeadResponse() {
|
||||||
ResponseEntity<Void> response = this.testClient.head();
|
ResponseEntity<Void> response = testClient.head();
|
||||||
assertThat(response).as("response was null").isNotNull();
|
assertThat(response).as("response was null").isNotNull();
|
||||||
assertThat(response.getStatusCode()).as("status code was wrong")
|
assertThat(response.getStatusCode()).as("status code was wrong")
|
||||||
.isEqualTo(HttpStatus.OK);
|
.isEqualTo(HttpStatus.OK);
|
||||||
@@ -310,7 +310,7 @@ public class FeignClientTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHttpEntity() {
|
public void testHttpEntity() {
|
||||||
HttpEntity<Hello> entity = this.testClient.getHelloEntity();
|
HttpEntity<Hello> entity = testClient.getHelloEntity();
|
||||||
assertThat(entity).as("entity was null").isNotNull();
|
assertThat(entity).as("entity was null").isNotNull();
|
||||||
Hello hello = entity.getBody();
|
Hello hello = entity.getBody();
|
||||||
assertThat(hello).as("hello was null").isNotNull();
|
assertThat(hello).as("hello was null").isNotNull();
|
||||||
@@ -320,7 +320,7 @@ public class FeignClientTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMoreComplexHeader() {
|
public void testMoreComplexHeader() {
|
||||||
String response = this.testClient.moreComplexContentType("{\"value\":\"OK\"}");
|
String response = testClient.moreComplexContentType("{\"value\":\"OK\"}");
|
||||||
assertThat(response).as("response was null").isNotNull();
|
assertThat(response).as("response was null").isNotNull();
|
||||||
assertThat(response).as("didn't respond with {\"value\":\"OK\"}")
|
assertThat(response).as("didn't respond with {\"value\":\"OK\"}")
|
||||||
.isEqualTo("{\"value\":\"OK\"}");
|
.isEqualTo("{\"value\":\"OK\"}");
|
||||||
@@ -328,7 +328,7 @@ public class FeignClientTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDecodeNotFound() {
|
public void testDecodeNotFound() {
|
||||||
ResponseEntity<String> response = this.decodingTestClient.notFound();
|
ResponseEntity<String> response = decodingTestClient.notFound();
|
||||||
assertThat(response).as("response was null").isNotNull();
|
assertThat(response).as("response was null").isNotNull();
|
||||||
assertThat(response.getStatusCode()).as("status code was wrong")
|
assertThat(response.getStatusCode()).as("status code was wrong")
|
||||||
.isEqualTo(HttpStatus.NOT_FOUND);
|
.isEqualTo(HttpStatus.NOT_FOUND);
|
||||||
@@ -337,35 +337,35 @@ public class FeignClientTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOptionalNotFound() {
|
public void testOptionalNotFound() {
|
||||||
Optional<String> s = this.decodingTestClient.optional();
|
Optional<String> s = decodingTestClient.optional();
|
||||||
assertThat(s).isNotPresent();
|
assertThat(s).isNotPresent();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testConvertingExpander() {
|
public void testConvertingExpander() {
|
||||||
assertThat(this.testClient.getToString(Arg.A)).isEqualTo(Arg.A.toString());
|
assertThat(testClient.getToString(Arg.A)).isEqualTo(Arg.A.toString());
|
||||||
assertThat(this.testClient.getToString(Arg.B)).isEqualTo(Arg.B.toString());
|
assertThat(testClient.getToString(Arg.B)).isEqualTo(Arg.B.toString());
|
||||||
|
|
||||||
assertThat(this.testClient.getToString(new OtherArg("foo"))).isEqualTo("bar");
|
assertThat(testClient.getToString(new OtherArg("foo"))).isEqualTo("bar");
|
||||||
List<OtherArg> args = new ArrayList<>();
|
List<OtherArg> args = new ArrayList<>();
|
||||||
args.add(new OtherArg("foo"));
|
args.add(new OtherArg("foo"));
|
||||||
args.add(new OtherArg("goo"));
|
args.add(new OtherArg("goo"));
|
||||||
List<String> expectedResult = new ArrayList<>();
|
List<String> expectedResult = new ArrayList<>();
|
||||||
expectedResult.add("bar");
|
expectedResult.add("bar");
|
||||||
expectedResult.add("goo");
|
expectedResult.add("goo");
|
||||||
assertThat(this.testClient.getToString(args)).isEqualTo(expectedResult);
|
assertThat(testClient.getToString(args)).isEqualTo(expectedResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHystrixFallbackWorks() {
|
public void testHystrixFallbackWorks() {
|
||||||
Hello hello = this.hystrixClient.fail();
|
Hello hello = hystrixClient.fail();
|
||||||
assertThat(hello).as("hello was null").isNotNull();
|
assertThat(hello).as("hello was null").isNotNull();
|
||||||
assertThat(hello.getMessage()).as("message was wrong").isEqualTo("fallback");
|
assertThat(hello.getMessage()).as("message was wrong").isEqualTo("fallback");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHystrixFallbackSingle() {
|
public void testHystrixFallbackSingle() {
|
||||||
Single<Hello> single = this.hystrixClient.failSingle();
|
Single<Hello> single = hystrixClient.failSingle();
|
||||||
assertThat(single).as("single was null").isNotNull();
|
assertThat(single).as("single was null").isNotNull();
|
||||||
Hello hello = single.toBlocking().value();
|
Hello hello = single.toBlocking().value();
|
||||||
assertThat(hello).as("hello was null").isNotNull();
|
assertThat(hello).as("hello was null").isNotNull();
|
||||||
@@ -375,7 +375,7 @@ public class FeignClientTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHystrixFallbackCommand() {
|
public void testHystrixFallbackCommand() {
|
||||||
HystrixCommand<Hello> command = this.hystrixClient.failCommand();
|
HystrixCommand<Hello> command = hystrixClient.failCommand();
|
||||||
assertThat(command).as("command was null").isNotNull();
|
assertThat(command).as("command was null").isNotNull();
|
||||||
Hello hello = command.execute();
|
Hello hello = command.execute();
|
||||||
assertThat(hello).as("hello was null").isNotNull();
|
assertThat(hello).as("hello was null").isNotNull();
|
||||||
@@ -385,7 +385,7 @@ public class FeignClientTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHystrixFallbackObservable() {
|
public void testHystrixFallbackObservable() {
|
||||||
Observable<Hello> observable = this.hystrixClient.failObservable();
|
Observable<Hello> observable = hystrixClient.failObservable();
|
||||||
assertThat(observable).as("observable was null").isNotNull();
|
assertThat(observable).as("observable was null").isNotNull();
|
||||||
Hello hello = observable.toBlocking().first();
|
Hello hello = observable.toBlocking().first();
|
||||||
assertThat(hello).as("hello was null").isNotNull();
|
assertThat(hello).as("hello was null").isNotNull();
|
||||||
@@ -395,7 +395,7 @@ public class FeignClientTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHystrixFallbackFuture() throws Exception {
|
public void testHystrixFallbackFuture() throws Exception {
|
||||||
Future<Hello> future = this.hystrixClient.failFuture();
|
Future<Hello> future = hystrixClient.failFuture();
|
||||||
assertThat(future).as("future was null").isNotNull();
|
assertThat(future).as("future was null").isNotNull();
|
||||||
Hello hello = future.get(1, TimeUnit.SECONDS);
|
Hello hello = future.get(1, TimeUnit.SECONDS);
|
||||||
assertThat(hello).as("hello was null").isNotNull();
|
assertThat(hello).as("hello was null").isNotNull();
|
||||||
@@ -405,7 +405,7 @@ public class FeignClientTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHystrixClientWithFallBackFactory() throws Exception {
|
public void testHystrixClientWithFallBackFactory() throws Exception {
|
||||||
Hello hello = this.hystrixClientWithFallBackFactory.fail();
|
Hello hello = hystrixClientWithFallBackFactory.fail();
|
||||||
assertThat(hello).as("hello was null").isNotNull();
|
assertThat(hello).as("hello was null").isNotNull();
|
||||||
assertThat(hello.getMessage()).as("hello#message was null").isNotNull();
|
assertThat(hello.getMessage()).as("hello#message was null").isNotNull();
|
||||||
assertThat(hello.getMessage().contains("500")).as(
|
assertThat(hello.getMessage().contains("500")).as(
|
||||||
@@ -415,22 +415,29 @@ public class FeignClientTests {
|
|||||||
|
|
||||||
@Test(expected = HystrixRuntimeException.class)
|
@Test(expected = HystrixRuntimeException.class)
|
||||||
public void testInvalidTypeHystrixFallbackFactory() throws Exception {
|
public void testInvalidTypeHystrixFallbackFactory() throws Exception {
|
||||||
this.invalidTypeHystrixClientWithFallBackFactory.fail();
|
invalidTypeHystrixClientWithFallBackFactory.fail();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = HystrixRuntimeException.class)
|
@Test(expected = HystrixRuntimeException.class)
|
||||||
public void testNullHystrixFallbackFactory() throws Exception {
|
public void testNullHystrixFallbackFactory() throws Exception {
|
||||||
this.nullHystrixClientWithFallBackFactory.fail();
|
nullHystrixClientWithFallBackFactory.fail();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFormURLEncoded() {
|
||||||
|
Hello hello = new Hello(HELLO_WORLD_1);
|
||||||
|
Hello response = testClient.postFormUrlEncoded(hello);
|
||||||
|
assertThat(response).isEqualTo(hello);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void namedFeignClientWorks() {
|
public void namedFeignClientWorks() {
|
||||||
assertThat(this.namedHystrixClient).as("namedHystrixClient was null").isNotNull();
|
assertThat(namedHystrixClient).as("namedHystrixClient was null").isNotNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testHystrixSetterFactory() {
|
public void testHystrixSetterFactory() {
|
||||||
HystrixCommand<List<Hello>> command = this.hystrixSetterFactoryClient
|
HystrixCommand<List<Hello>> command = hystrixSetterFactoryClient
|
||||||
.getHellosHystrix();
|
.getHellosHystrix();
|
||||||
assertThat(command).as("command was null").isNotNull();
|
assertThat(command).as("command was null").isNotNull();
|
||||||
String setterPrefix = TestHystrixSetterFactoryClientConfig.SETTER_PREFIX;
|
String setterPrefix = TestHystrixSetterFactoryClientConfig.SETTER_PREFIX;
|
||||||
@@ -449,13 +456,13 @@ public class FeignClientTests {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSingleRequestPart() {
|
public void testSingleRequestPart() {
|
||||||
String response = this.multipartClient.singlePart("abc");
|
String response = multipartClient.singlePart("abc");
|
||||||
assertThat(response).isEqualTo("abc");
|
assertThat(response).isEqualTo("abc");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSinglePojoRequestPart() {
|
public void testSinglePojoRequestPart() {
|
||||||
String response = this.multipartClient.singlePojoPart(new Hello(HELLO_WORLD_1));
|
String response = multipartClient.singlePojoPart(new Hello(HELLO_WORLD_1));
|
||||||
assertThat(response).isEqualTo(HELLO_WORLD_1);
|
assertThat(response).isEqualTo(HELLO_WORLD_1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -463,7 +470,7 @@ public class FeignClientTests {
|
|||||||
public void testMultipleRequestParts() {
|
public void testMultipleRequestParts() {
|
||||||
MockMultipartFile file = new MockMultipartFile("file", "hello.bin", null,
|
MockMultipartFile file = new MockMultipartFile("file", "hello.bin", null,
|
||||||
"hello".getBytes());
|
"hello".getBytes());
|
||||||
String response = this.multipartClient.multipart("abc", "123", file);
|
String response = multipartClient.multipart("abc", "123", file);
|
||||||
assertThat(response).isEqualTo("abc123hello.bin");
|
assertThat(response).isEqualTo("abc123hello.bin");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -473,8 +480,7 @@ public class FeignClientTests {
|
|||||||
Hello pojo2 = new Hello(OI_TERRA_2);
|
Hello pojo2 = new Hello(OI_TERRA_2);
|
||||||
MockMultipartFile file = new MockMultipartFile("file", "hello.bin", null,
|
MockMultipartFile file = new MockMultipartFile("file", "hello.bin", null,
|
||||||
"hello".getBytes());
|
"hello".getBytes());
|
||||||
String response = this.multipartClient.multipartPojo("abc", "123", pojo1, pojo2,
|
String response = multipartClient.multipartPojo("abc", "123", pojo1, pojo2, file);
|
||||||
file);
|
|
||||||
assertThat(response).isEqualTo("abc123hello world 1oi terra 2hello.bin");
|
assertThat(response).isEqualTo("abc123hello world 1oi terra 2hello.bin");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -483,10 +489,10 @@ public class FeignClientTests {
|
|||||||
List<MultipartFile> multipartFiles = Arrays.asList(
|
List<MultipartFile> multipartFiles = Arrays.asList(
|
||||||
new MockMultipartFile("file1", "hello1.bin", null, "hello".getBytes()),
|
new MockMultipartFile("file1", "hello1.bin", null, "hello".getBytes()),
|
||||||
new MockMultipartFile("file2", "hello2.bin", null, "hello".getBytes()));
|
new MockMultipartFile("file2", "hello2.bin", null, "hello".getBytes()));
|
||||||
String partNames = this.multipartClient
|
String partNames = multipartClient
|
||||||
.requestPartListOfMultipartFilesReturnsPartNames(multipartFiles);
|
.requestPartListOfMultipartFilesReturnsPartNames(multipartFiles);
|
||||||
assertThat(partNames).isEqualTo("files,files");
|
assertThat(partNames).isEqualTo("files,files");
|
||||||
String fileNames = this.multipartClient
|
String fileNames = multipartClient
|
||||||
.requestPartListOfMultipartFilesReturnsFileNames(multipartFiles);
|
.requestPartListOfMultipartFilesReturnsFileNames(multipartFiles);
|
||||||
assertThat(fileNames).contains("hello1.bin", "hello2.bin");
|
assertThat(fileNames).contains("hello1.bin", "hello2.bin");
|
||||||
}
|
}
|
||||||
@@ -499,9 +505,8 @@ public class FeignClientTests {
|
|||||||
"hello".getBytes());
|
"hello".getBytes());
|
||||||
MockMultipartFile file2 = new MockMultipartFile("file2", "hello2.bin", null,
|
MockMultipartFile file2 = new MockMultipartFile("file2", "hello2.bin", null,
|
||||||
"hello".getBytes());
|
"hello".getBytes());
|
||||||
String response = this.multipartClient
|
String response = multipartClient.requestPartListOfPojosAndListOfMultipartFiles(
|
||||||
.requestPartListOfPojosAndListOfMultipartFiles(
|
Arrays.asList(pojo1, pojo2), Arrays.asList(file1, file2));
|
||||||
Arrays.asList(pojo1, pojo2), Arrays.asList(file1, file2));
|
|
||||||
assertThat(response).isEqualTo("hello world 1oi terra 2hello1.binhello2.bin");
|
assertThat(response).isEqualTo("hello world 1oi terra 2hello1.binhello2.bin");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -510,7 +515,7 @@ public class FeignClientTests {
|
|||||||
String partName = UUID.randomUUID().toString();
|
String partName = UUID.randomUUID().toString();
|
||||||
MockMultipartFile file1 = new MockMultipartFile(partName, "hello1.bin", null,
|
MockMultipartFile file1 = new MockMultipartFile(partName, "hello1.bin", null,
|
||||||
"hello".getBytes());
|
"hello".getBytes());
|
||||||
String response = this.multipartClient.requestBodySingleMultipartFile(file1);
|
String response = multipartClient.requestBodySingleMultipartFile(file1);
|
||||||
assertThat(response).isEqualTo(partName);
|
assertThat(response).isEqualTo(partName);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -520,7 +525,7 @@ public class FeignClientTests {
|
|||||||
"hello".getBytes());
|
"hello".getBytes());
|
||||||
MockMultipartFile file2 = new MockMultipartFile("file2", "hello2.bin", null,
|
MockMultipartFile file2 = new MockMultipartFile("file2", "hello2.bin", null,
|
||||||
"hello".getBytes());
|
"hello".getBytes());
|
||||||
String response = this.multipartClient
|
String response = multipartClient
|
||||||
.requestBodyListOfMultipartFiles(Arrays.asList(file1, file2));
|
.requestBodyListOfMultipartFiles(Arrays.asList(file1, file2));
|
||||||
assertThat(response).contains("file1", "file2");
|
assertThat(response).contains("file1", "file2");
|
||||||
}
|
}
|
||||||
@@ -535,7 +540,7 @@ public class FeignClientTests {
|
|||||||
form.put("file1", file1);
|
form.put("file1", file1);
|
||||||
form.put("file2", file2);
|
form.put("file2", file2);
|
||||||
form.put("hello", "world");
|
form.put("hello", "world");
|
||||||
String response = this.multipartClient.requestBodyMap(form);
|
String response = multipartClient.requestBodyMap(form);
|
||||||
assertThat(response).contains("file1", "file2", "hello");
|
assertThat(response).contains("file1", "file2", "hello");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -544,7 +549,7 @@ public class FeignClientTests {
|
|||||||
MockMultipartFile file = new MockMultipartFile("file1", "hello1.bin", null,
|
MockMultipartFile file = new MockMultipartFile("file1", "hello1.bin", null,
|
||||||
"hello".getBytes());
|
"hello".getBytes());
|
||||||
expected.expectCause(instanceOf(EncodeException.class));
|
expected.expectCause(instanceOf(EncodeException.class));
|
||||||
this.multipartClient.invalid(file);
|
multipartClient.invalid(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected enum Arg {
|
protected enum Arg {
|
||||||
@@ -615,6 +620,10 @@ public class FeignClientTests {
|
|||||||
@RequestMapping(method = RequestMethod.GET, path = "/tostring")
|
@RequestMapping(method = RequestMethod.GET, path = "/tostring")
|
||||||
String getToString(@RequestParam("arg") Arg arg);
|
String getToString(@RequestParam("arg") Arg arg);
|
||||||
|
|
||||||
|
@PostMapping(path = "/form-urlencoded",
|
||||||
|
consumes = APPLICATION_FORM_URLENCODED_VALUE)
|
||||||
|
Hello postFormUrlEncoded(Hello hello);
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, path = "/tostring2")
|
@RequestMapping(method = RequestMethod.GET, path = "/tostring2")
|
||||||
String getToString(@RequestParam("arg") OtherArg arg);
|
String getToString(@RequestParam("arg") OtherArg arg);
|
||||||
|
|
||||||
@@ -776,7 +785,7 @@ public class FeignClientTests {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return this.value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -810,13 +819,9 @@ public class FeignClientTests {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public HystrixClientWithFallBackFactory create(final Throwable cause) {
|
public HystrixClientWithFallBackFactory create(final Throwable cause) {
|
||||||
return new HystrixClientWithFallBackFactory() {
|
return () -> {
|
||||||
@Override
|
assertThat(cause).isNotNull().as("Cause was null");
|
||||||
public Hello fail() {
|
return new Hello("Hello from the fallback side: " + cause.getMessage());
|
||||||
assertThat(cause).isNotNull().as("Cause was null");
|
|
||||||
return new Hello(
|
|
||||||
"Hello from the fallback side: " + cause.getMessage());
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -876,18 +881,15 @@ public class FeignClientTests {
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public SetterFactory commandKeyIsRequestLineSetterFactory() {
|
public SetterFactory commandKeyIsRequestLineSetterFactory() {
|
||||||
return new SetterFactory() {
|
return (target, method) -> {
|
||||||
@Override
|
String groupKey = SETTER_PREFIX + target.name();
|
||||||
public HystrixCommand.Setter create(Target<?> target, Method method) {
|
RequestMapping requestMapping = method
|
||||||
String groupKey = SETTER_PREFIX + target.name();
|
.getAnnotation(RequestMapping.class);
|
||||||
RequestMapping requestMapping = method
|
String commandKey = SETTER_PREFIX + requestMapping.method()[0] + " "
|
||||||
.getAnnotation(RequestMapping.class);
|
+ requestMapping.path()[0];
|
||||||
String commandKey = SETTER_PREFIX + requestMapping.method()[0] + " "
|
return HystrixCommand.Setter
|
||||||
+ requestMapping.path()[0];
|
.withGroupKey(HystrixCommandGroupKey.Factory.asKey(groupKey))
|
||||||
return HystrixCommand.Setter
|
.andCommandKey(HystrixCommandKey.Factory.asKey(commandKey));
|
||||||
.withGroupKey(HystrixCommandGroupKey.Factory.asKey(groupKey))
|
|
||||||
.andCommandKey(HystrixCommandKey.Factory.asKey(commandKey));
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1154,6 +1156,12 @@ public class FeignClientTests {
|
|||||||
return result.toString();
|
return result.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping(path = "/form-urlencoded",
|
||||||
|
consumes = APPLICATION_FORM_URLENCODED_VALUE)
|
||||||
|
Hello postFormUrlEncoded(Hello hello) {
|
||||||
|
return hello;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Hello {
|
public static class Hello {
|
||||||
@@ -1168,7 +1176,7 @@ public class FeignClientTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String getMessage() {
|
public String getMessage() {
|
||||||
return this.message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setMessage(String message) {
|
public void setMessage(String message) {
|
||||||
@@ -1184,12 +1192,12 @@ public class FeignClientTests {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
Hello that = (Hello) o;
|
Hello that = (Hello) o;
|
||||||
return Objects.equals(this.message, that.message);
|
return Objects.equals(message, that.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hash(this.message);
|
return Objects.hash(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1213,7 +1221,7 @@ public class FeignClientTests {
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public ServerList<Server> ribbonServerList() {
|
public ServerList<Server> ribbonServerList() {
|
||||||
return new StaticServerList<>(new Server("localhost", this.port));
|
return new StaticServerList<>(new Server("localhost", port));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,11 +6,11 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<artifactId>spring-cloud-dependencies-parent</artifactId>
|
<artifactId>spring-cloud-dependencies-parent</artifactId>
|
||||||
<groupId>org.springframework.cloud</groupId>
|
<groupId>org.springframework.cloud</groupId>
|
||||||
<version>2.3.4.RELEASE</version>
|
<version>2.3.6.BUILD-SNAPSHOT</version>
|
||||||
<relativePath/>
|
<relativePath/>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>spring-cloud-openfeign-dependencies</artifactId>
|
<artifactId>spring-cloud-openfeign-dependencies</artifactId>
|
||||||
<version>2.2.8.RELEASE</version>
|
<version>2.2.11.BUILD-SNAPSHOT</version>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
<name>spring-cloud-openfeign-dependencies</name>
|
<name>spring-cloud-openfeign-dependencies</name>
|
||||||
<description>Spring Cloud OpenFeign Dependencies</description>
|
<description>Spring Cloud OpenFeign Dependencies</description>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<parent>
|
<parent>
|
||||||
<groupId>org.springframework.cloud</groupId>
|
<groupId>org.springframework.cloud</groupId>
|
||||||
<artifactId>spring-cloud-openfeign</artifactId>
|
<artifactId>spring-cloud-openfeign</artifactId>
|
||||||
<version>2.2.8.RELEASE</version>
|
<version>2.2.11.BUILD-SNAPSHOT</version>
|
||||||
<relativePath>..</relativePath>
|
<relativePath>..</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||||
|
|||||||
Reference in New Issue
Block a user