Compare commits
50
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3bba08931d | ||
|
|
0853ccc1e5 | ||
|
|
13f91320b1 | ||
|
|
7af0efd569 | ||
|
|
70a9002002 | ||
|
|
ad892a23f0 | ||
|
|
c0f314a5f0 | ||
|
|
56dc4e07e4 | ||
|
|
9167752bfb | ||
|
|
127c866616 | ||
|
|
0e6b33f480 | ||
|
|
17d0161faf | ||
|
|
d6783a6f1e | ||
|
|
548e4d55ef | ||
|
|
55ceafae4d | ||
|
|
0c87527ea5 | ||
|
|
a2c473db2a | ||
|
|
ae33802a4b | ||
|
|
c761919bc9 | ||
|
|
998baed0d3 | ||
|
|
4fc80e6b01 | ||
|
|
c101fd2c6e | ||
|
|
71930fd9f0 | ||
|
|
b5283e2f88 | ||
|
|
6aeb1ff676 | ||
|
|
44c63798b0 | ||
|
|
769b38c5c1 | ||
|
|
3c402201ec | ||
|
|
deb150ed88 | ||
|
|
1275875ddb | ||
|
|
c4b9492a9b | ||
|
|
3acf5f9e92 | ||
|
|
e9e38d0274 | ||
|
|
28b50401c5 | ||
|
|
6479db0a54 | ||
|
|
f7e490c466 | ||
|
|
d60cda824d | ||
|
|
190f5a9083 | ||
|
|
1005749eb5 | ||
|
|
6de9fdd3e1 | ||
|
|
df1f982046 | ||
|
|
baf7cf95f2 | ||
|
|
45861dd657 | ||
|
|
00ea88c67f | ||
|
|
d897b18e16 | ||
|
|
8c08204c78 | ||
|
|
1f5bdd4224 | ||
|
|
2f43715f6f | ||
|
|
280291ec93 | ||
|
|
0de9dd614d |
+11
-13
@@ -5,9 +5,9 @@ name: Build
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
branches: [ main ]
|
branches: [ 3.0.x ]
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ main ]
|
branches: [ 3.0.x ]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
@@ -20,16 +20,14 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Set up JDK 1.8
|
- name: Set up JDK ${{ matrix.java }}
|
||||||
uses: actions/setup-java@v1
|
uses: actions/setup-java@v2
|
||||||
with:
|
with:
|
||||||
java-version: 1.8
|
distribution: 'zulu'
|
||||||
- name: Cache local Maven repository
|
java-version: ${{ matrix.java }}
|
||||||
uses: actions/cache@v2
|
cache: 'maven'
|
||||||
with:
|
|
||||||
path: ~/.m2/repository
|
|
||||||
key: ${{ runner.os }}-maven-${{ hashFiles('**/pom.xml') }}
|
|
||||||
restore-keys: |
|
|
||||||
${{ runner.os }}-maven-
|
|
||||||
- name: Build with Maven
|
- name: Build with Maven
|
||||||
run: ./mvnw clean install -B -U
|
run: ./mvnw clean install -B -U -P sonar
|
||||||
|
- uses: codecov/codecov-action@v1
|
||||||
|
with:
|
||||||
|
fail_ci_if_error: true
|
||||||
|
|||||||
+2
-16
@@ -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
|
||||||
|
|
||||||
|
|||||||
+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>3.0.3</version>
|
<version>3.0.7-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>spring-cloud-openfeign-docs</artifactId>
|
<artifactId>spring-cloud-openfeign-docs</artifactId>
|
||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|||||||
@@ -66,10 +66,15 @@ The load-balancer client above will want to discover the physical addresses
|
|||||||
for the "stores" service. If your application is a Eureka client then
|
for the "stores" service. If your application is a Eureka client then
|
||||||
it will resolve the service in the Eureka service registry. If you
|
it will resolve the service in the Eureka service registry. If you
|
||||||
don't want to use Eureka, you can configure a list of servers
|
don't want to use Eureka, you can configure a list of servers
|
||||||
in your external configuration using https://cloud.spring.io/spring-cloud-static/spring-cloud-commons/current/reference/html/#simplediscoveryclient[`SimpleDiscoveryClient`].
|
in your external configuration using https://docs.spring.io/spring-cloud-commons/docs/current/reference/html/#simplediscoveryclient[`SimpleDiscoveryClient`].
|
||||||
|
|
||||||
Spring Cloud OpenFeign supports all the features available for the blocking mode of Spring Cloud LoadBalancer. You can read more about them in the https://docs.spring.io/spring-cloud-commons/docs/current/reference/html/#spring-cloud-loadbalancer[project documentation].
|
Spring Cloud OpenFeign supports all the features available for the blocking mode of Spring Cloud LoadBalancer. You can read more about them in the https://docs.spring.io/spring-cloud-commons/docs/current/reference/html/#spring-cloud-loadbalancer[project documentation].
|
||||||
|
|
||||||
|
TIP: To use `@EnableFeignClients` annotation on `@Configuration`-annotated-classes, make sure to specify where the clients are located, for example:
|
||||||
|
`@EnableFeignClients(basePackages = "com.example.clients")`
|
||||||
|
or list them explicitly:
|
||||||
|
`@EnableFeignClients(clients = InventoryServiceFeignClient.class)`
|
||||||
|
|
||||||
[[spring-cloud-feign-overriding-defaults]]
|
[[spring-cloud-feign-overriding-defaults]]
|
||||||
=== Overriding Feign Defaults
|
=== Overriding Feign Defaults
|
||||||
|
|
||||||
@@ -343,7 +348,22 @@ public class FooConfiguration {
|
|||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
The circuit breaker name follows this pattern `<feignClientName>#<calledMethod>`. When calling a `@FeignClient` with name `foo` and the called interface method is `bar` then the circuit breaker name will be `foo_bar`.
|
The circuit breaker name follows this pattern `<feignClientClassName>#<calledMethod>(<parameterTypes>)`. When calling a `@FeignClient` with `FooClient` interface and the called interface method that has no parameters is `bar` then the circuit breaker name will be `FooClient#bar()`.
|
||||||
|
|
||||||
|
NOTE: As of 2020.0.2, the circuit breaker name pattern has changed from `<feignClientName>_<calledMethod>`.
|
||||||
|
Using `CircuitBreakerNameResolver` introduced in 2020.0.4, circuit breaker names can retain the old pattern.
|
||||||
|
|
||||||
|
Providing a bean of `CircuitBreakerNameResolver`, you can change the circuit breaker name pattern.
|
||||||
|
[source,java,indent=0]
|
||||||
|
----
|
||||||
|
@Configuration
|
||||||
|
public class FooConfiguration {
|
||||||
|
@Bean
|
||||||
|
public CircuitBreakerNameResolver circuitBreakerNameResolver() {
|
||||||
|
return (String feignClientName, Target<?> target, Method method) -> feignClientName + "_" + method.getName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
To enable Spring Cloud CircuitBreaker group set the `feign.circuitbreaker.group.enabled` property to `true` (by default `false`).
|
To enable Spring Cloud CircuitBreaker group set the `feign.circuitbreaker.group.enabled` property to `true` (by default `false`).
|
||||||
|
|
||||||
@@ -471,10 +491,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>3.0.3</version>
|
<version>3.0.7-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>3.0.3</version>
|
<version>3.0.5</version>
|
||||||
<relativePath/>
|
<relativePath/>
|
||||||
</parent>
|
</parent>
|
||||||
<scm>
|
<scm>
|
||||||
@@ -26,7 +26,7 @@
|
|||||||
<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>3.0.3</spring-cloud-commons.version>
|
<spring-cloud-commons.version>3.0.6-SNAPSHOT</spring-cloud-commons.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>3.0.3</version>
|
<version>3.0.7-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>
|
||||||
@@ -183,13 +183,13 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.google.protobuf</groupId>
|
<groupId>com.google.protobuf</groupId>
|
||||||
<artifactId>protobuf-java</artifactId>
|
<artifactId>protobuf-java</artifactId>
|
||||||
<version>3.14.0</version>
|
<version>3.19.1</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.vavr</groupId>
|
<groupId>io.vavr</groupId>
|
||||||
<artifactId>vavr</artifactId>
|
<artifactId>vavr</artifactId>
|
||||||
<version>0.10.3</version>
|
<version>0.10.4</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|||||||
+34
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013-2021 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.cloud.openfeign;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
import feign.Target;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Used to resolve a circuitbreaker name which will be used in
|
||||||
|
* {@link org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory}.
|
||||||
|
*
|
||||||
|
* @author Kwangyong Kim
|
||||||
|
* @since 2020.0.4
|
||||||
|
*/
|
||||||
|
public interface CircuitBreakerNameResolver {
|
||||||
|
|
||||||
|
String resolveCircuitBreakerName(String feignClientName, Target<?> target, Method method);
|
||||||
|
|
||||||
|
}
|
||||||
+22
-2
@@ -17,6 +17,7 @@
|
|||||||
package org.springframework.cloud.openfeign;
|
package org.springframework.cloud.openfeign;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Timer;
|
import java.util.Timer;
|
||||||
@@ -29,6 +30,7 @@ import com.fasterxml.jackson.databind.Module;
|
|||||||
import feign.Client;
|
import feign.Client;
|
||||||
import feign.Feign;
|
import feign.Feign;
|
||||||
import feign.RequestInterceptor;
|
import feign.RequestInterceptor;
|
||||||
|
import feign.Target;
|
||||||
import feign.hc5.ApacheHttp5Client;
|
import feign.hc5.ApacheHttp5Client;
|
||||||
import feign.httpclient.ApacheHttpClient;
|
import feign.httpclient.ApacheHttpClient;
|
||||||
import feign.okhttp.OkHttpClient;
|
import feign.okhttp.OkHttpClient;
|
||||||
@@ -79,6 +81,7 @@ import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResour
|
|||||||
* @author Olga Maciaszek-Sharma
|
* @author Olga Maciaszek-Sharma
|
||||||
* @author Nguyen Ky Thanh
|
* @author Nguyen Ky Thanh
|
||||||
* @author Andrii Bohutskyi
|
* @author Andrii Bohutskyi
|
||||||
|
* @author Kwangyong Kim
|
||||||
*/
|
*/
|
||||||
@Configuration(proxyBeanMethods = false)
|
@Configuration(proxyBeanMethods = false)
|
||||||
@ConditionalOnClass(Feign.class)
|
@ConditionalOnClass(Feign.class)
|
||||||
@@ -146,12 +149,29 @@ public class FeignAutoConfiguration {
|
|||||||
return new DefaultTargeter();
|
return new DefaultTargeter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean(CircuitBreakerNameResolver.class)
|
||||||
|
public CircuitBreakerNameResolver circuitBreakerNameResolver() {
|
||||||
|
return new DefaultCircuitBreakerNameResolver();
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@ConditionalOnMissingBean
|
@ConditionalOnMissingBean
|
||||||
@ConditionalOnBean(CircuitBreakerFactory.class)
|
@ConditionalOnBean(CircuitBreakerFactory.class)
|
||||||
public Targeter circuitBreakerFeignTargeter(CircuitBreakerFactory circuitBreakerFactory,
|
public Targeter circuitBreakerFeignTargeter(CircuitBreakerFactory circuitBreakerFactory,
|
||||||
@Value("${feign.circuitbreaker.group.enabled:false}") boolean circuitBreakerGroupEnabled) {
|
@Value("${feign.circuitbreaker.group.enabled:false}") boolean circuitBreakerGroupEnabled,
|
||||||
return new FeignCircuitBreakerTargeter(circuitBreakerFactory, circuitBreakerGroupEnabled);
|
CircuitBreakerNameResolver circuitBreakerNameResolver) {
|
||||||
|
return new FeignCircuitBreakerTargeter(circuitBreakerFactory, circuitBreakerGroupEnabled,
|
||||||
|
circuitBreakerNameResolver);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class DefaultCircuitBreakerNameResolver implements CircuitBreakerNameResolver {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String resolveCircuitBreakerName(String feignClientName, Target<?> target, Method method) {
|
||||||
|
return Feign.configKey(target.type(), method);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-3
@@ -27,6 +27,7 @@ import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory;
|
|||||||
*
|
*
|
||||||
* @author Marcin Grzejszczak
|
* @author Marcin Grzejszczak
|
||||||
* @author Andrii Bohutskyi
|
* @author Andrii Bohutskyi
|
||||||
|
* @author Kwangyong Kim
|
||||||
* @since 3.0.0
|
* @since 3.0.0
|
||||||
*/
|
*/
|
||||||
public final class FeignCircuitBreaker {
|
public final class FeignCircuitBreaker {
|
||||||
@@ -53,6 +54,8 @@ public final class FeignCircuitBreaker {
|
|||||||
|
|
||||||
private boolean circuitBreakerGroupEnabled;
|
private boolean circuitBreakerGroupEnabled;
|
||||||
|
|
||||||
|
private CircuitBreakerNameResolver circuitBreakerNameResolver;
|
||||||
|
|
||||||
Builder circuitBreakerFactory(CircuitBreakerFactory circuitBreakerFactory) {
|
Builder circuitBreakerFactory(CircuitBreakerFactory circuitBreakerFactory) {
|
||||||
this.circuitBreakerFactory = circuitBreakerFactory;
|
this.circuitBreakerFactory = circuitBreakerFactory;
|
||||||
return this;
|
return this;
|
||||||
@@ -68,6 +71,11 @@ public final class FeignCircuitBreaker {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Builder circuitBreakerNameResolver(CircuitBreakerNameResolver circuitBreakerNameResolver) {
|
||||||
|
this.circuitBreakerNameResolver = circuitBreakerNameResolver;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public <T> T target(Target<T> target, T fallback) {
|
public <T> T target(Target<T> target, T fallback) {
|
||||||
return build(fallback != null ? new FallbackFactory.Default<T>(fallback) : null).newInstance(target);
|
return build(fallback != null ? new FallbackFactory.Default<T>(fallback) : null).newInstance(target);
|
||||||
}
|
}
|
||||||
@@ -82,9 +90,9 @@ public final class FeignCircuitBreaker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Feign build(final FallbackFactory<?> nullableFallbackFactory) {
|
public Feign build(final FallbackFactory<?> nullableFallbackFactory) {
|
||||||
super.invocationHandlerFactory(
|
super.invocationHandlerFactory((target, dispatch) -> new FeignCircuitBreakerInvocationHandler(
|
||||||
(target, dispatch) -> new FeignCircuitBreakerInvocationHandler(circuitBreakerFactory,
|
circuitBreakerFactory, feignClientName, target, dispatch, nullableFallbackFactory,
|
||||||
feignClientName, target, dispatch, nullableFallbackFactory, circuitBreakerGroupEnabled));
|
circuitBreakerGroupEnabled, circuitBreakerNameResolver));
|
||||||
return super.build();
|
return super.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
-7
@@ -24,7 +24,6 @@ import java.util.Map;
|
|||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import feign.Feign;
|
|
||||||
import feign.InvocationHandlerFactory;
|
import feign.InvocationHandlerFactory;
|
||||||
import feign.Target;
|
import feign.Target;
|
||||||
|
|
||||||
@@ -51,9 +50,11 @@ class FeignCircuitBreakerInvocationHandler implements InvocationHandler {
|
|||||||
|
|
||||||
private final boolean circuitBreakerGroupEnabled;
|
private final boolean circuitBreakerGroupEnabled;
|
||||||
|
|
||||||
|
private final CircuitBreakerNameResolver circuitBreakerNameResolver;
|
||||||
|
|
||||||
FeignCircuitBreakerInvocationHandler(CircuitBreakerFactory factory, String feignClientName, Target<?> target,
|
FeignCircuitBreakerInvocationHandler(CircuitBreakerFactory factory, String feignClientName, Target<?> target,
|
||||||
Map<Method, InvocationHandlerFactory.MethodHandler> dispatch, FallbackFactory<?> nullableFallbackFactory,
|
Map<Method, InvocationHandlerFactory.MethodHandler> dispatch, FallbackFactory<?> nullableFallbackFactory,
|
||||||
boolean circuitBreakerGroupEnabled) {
|
boolean circuitBreakerGroupEnabled, CircuitBreakerNameResolver circuitBreakerNameResolver) {
|
||||||
this.factory = factory;
|
this.factory = factory;
|
||||||
this.feignClientName = feignClientName;
|
this.feignClientName = feignClientName;
|
||||||
this.target = checkNotNull(target, "target");
|
this.target = checkNotNull(target, "target");
|
||||||
@@ -61,6 +62,7 @@ class FeignCircuitBreakerInvocationHandler implements InvocationHandler {
|
|||||||
this.fallbackMethodMap = toFallbackMethod(dispatch);
|
this.fallbackMethodMap = toFallbackMethod(dispatch);
|
||||||
this.nullableFallbackFactory = nullableFallbackFactory;
|
this.nullableFallbackFactory = nullableFallbackFactory;
|
||||||
this.circuitBreakerGroupEnabled = circuitBreakerGroupEnabled;
|
this.circuitBreakerGroupEnabled = circuitBreakerGroupEnabled;
|
||||||
|
this.circuitBreakerNameResolver = circuitBreakerNameResolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -82,7 +84,8 @@ class FeignCircuitBreakerInvocationHandler implements InvocationHandler {
|
|||||||
else if ("toString".equals(method.getName())) {
|
else if ("toString".equals(method.getName())) {
|
||||||
return toString();
|
return toString();
|
||||||
}
|
}
|
||||||
String circuitName = Feign.configKey(target.type(), method);
|
|
||||||
|
String circuitName = circuitBreakerNameResolver.resolveCircuitBreakerName(feignClientName, target, method);
|
||||||
CircuitBreaker circuitBreaker = circuitBreakerGroupEnabled ? factory.create(circuitName, feignClientName)
|
CircuitBreaker circuitBreaker = circuitBreakerGroupEnabled ? factory.create(circuitName, feignClientName)
|
||||||
: factory.create(circuitName);
|
: factory.create(circuitName);
|
||||||
Supplier<Object> supplier = asSupplier(method, args);
|
Supplier<Object> supplier = asSupplier(method, args);
|
||||||
@@ -106,7 +109,7 @@ class FeignCircuitBreakerInvocationHandler implements InvocationHandler {
|
|||||||
return () -> {
|
return () -> {
|
||||||
try {
|
try {
|
||||||
RequestContextHolder.setRequestAttributes(requestAttributes);
|
RequestContextHolder.setRequestAttributes(requestAttributes);
|
||||||
return this.dispatch.get(method).invoke(args);
|
return dispatch.get(method).invoke(args);
|
||||||
}
|
}
|
||||||
catch (RuntimeException throwable) {
|
catch (RuntimeException throwable) {
|
||||||
throw throwable;
|
throw throwable;
|
||||||
@@ -114,9 +117,6 @@ class FeignCircuitBreakerInvocationHandler implements InvocationHandler {
|
|||||||
catch (Throwable throwable) {
|
catch (Throwable throwable) {
|
||||||
throw new RuntimeException(throwable);
|
throw new RuntimeException(throwable);
|
||||||
}
|
}
|
||||||
finally {
|
|
||||||
RequestContextHolder.resetRequestAttributes();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+7
-2
@@ -29,9 +29,13 @@ class FeignCircuitBreakerTargeter implements Targeter {
|
|||||||
|
|
||||||
private final boolean circuitBreakerGroupEnabled;
|
private final boolean circuitBreakerGroupEnabled;
|
||||||
|
|
||||||
FeignCircuitBreakerTargeter(CircuitBreakerFactory circuitBreakerFactory, boolean circuitBreakerGroupEnabled) {
|
private final CircuitBreakerNameResolver circuitBreakerNameResolver;
|
||||||
|
|
||||||
|
FeignCircuitBreakerTargeter(CircuitBreakerFactory circuitBreakerFactory, boolean circuitBreakerGroupEnabled,
|
||||||
|
CircuitBreakerNameResolver circuitBreakerNameResolver) {
|
||||||
this.circuitBreakerFactory = circuitBreakerFactory;
|
this.circuitBreakerFactory = circuitBreakerFactory;
|
||||||
this.circuitBreakerGroupEnabled = circuitBreakerGroupEnabled;
|
this.circuitBreakerGroupEnabled = circuitBreakerGroupEnabled;
|
||||||
|
this.circuitBreakerNameResolver = circuitBreakerNameResolver;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -85,7 +89,8 @@ class FeignCircuitBreakerTargeter implements Targeter {
|
|||||||
|
|
||||||
private FeignCircuitBreaker.Builder builder(String feignClientName, FeignCircuitBreaker.Builder builder) {
|
private FeignCircuitBreaker.Builder builder(String feignClientName, FeignCircuitBreaker.Builder builder) {
|
||||||
return builder.circuitBreakerFactory(circuitBreakerFactory).feignClientName(feignClientName)
|
return builder.circuitBreakerFactory(circuitBreakerFactory).feignClientName(feignClientName)
|
||||||
.circuitBreakerGroupEnabled(circuitBreakerGroupEnabled);
|
.circuitBreakerGroupEnabled(circuitBreakerGroupEnabled)
|
||||||
|
.circuitBreakerNameResolver(circuitBreakerNameResolver);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+35
-12
@@ -17,6 +17,7 @@
|
|||||||
package org.springframework.cloud.openfeign;
|
package org.springframework.cloud.openfeign;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
@@ -276,13 +277,8 @@ public class FeignClientFactoryBean
|
|||||||
builder.encoder(getOrInstantiate(config.getEncoder()));
|
builder.encoder(getOrInstantiate(config.getEncoder()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Objects.nonNull(config.getDefaultRequestHeaders())) {
|
addDefaultRequestHeaders(config, builder);
|
||||||
builder.requestInterceptor(requestTemplate -> requestTemplate.headers(config.getDefaultRequestHeaders()));
|
addDefaultQueryParams(config, builder);
|
||||||
}
|
|
||||||
|
|
||||||
if (Objects.nonNull(config.getDefaultQueryParameters())) {
|
|
||||||
builder.requestInterceptor(requestTemplate -> requestTemplate.queries(config.getDefaultQueryParameters()));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Objects.nonNull(config.getDecoder())) {
|
if (Objects.nonNull(config.getDecoder())) {
|
||||||
builder.decoder(getOrInstantiate(config.getDecoder()));
|
builder.decoder(getOrInstantiate(config.getDecoder()));
|
||||||
@@ -301,6 +297,35 @@ public class FeignClientFactoryBean
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addDefaultQueryParams(FeignClientProperties.FeignClientConfiguration config, Feign.Builder builder) {
|
||||||
|
Map<String, Collection<String>> defaultQueryParameters = config.getDefaultQueryParameters();
|
||||||
|
if (Objects.nonNull(defaultQueryParameters)) {
|
||||||
|
builder.requestInterceptor(requestTemplate -> {
|
||||||
|
Map<String, Collection<String>> queries = requestTemplate.queries();
|
||||||
|
defaultQueryParameters.keySet().forEach(key -> {
|
||||||
|
if (!queries.containsKey(key)) {
|
||||||
|
requestTemplate.query(key, defaultQueryParameters.get(key));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addDefaultRequestHeaders(FeignClientProperties.FeignClientConfiguration config,
|
||||||
|
Feign.Builder builder) {
|
||||||
|
Map<String, Collection<String>> defaultRequestHeaders = config.getDefaultRequestHeaders();
|
||||||
|
if (Objects.nonNull(defaultRequestHeaders)) {
|
||||||
|
builder.requestInterceptor(requestTemplate -> {
|
||||||
|
Map<String, Collection<String>> headers = requestTemplate.headers();
|
||||||
|
defaultRequestHeaders.keySet().forEach(key -> {
|
||||||
|
if (!headers.containsKey(key)) {
|
||||||
|
requestTemplate.header(key, defaultRequestHeaders.get(key));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private <T> T getOrInstantiate(Class<T> tClass) {
|
private <T> T getOrInstantiate(Class<T> tClass) {
|
||||||
try {
|
try {
|
||||||
return beanFactory != null ? beanFactory.getBean(tClass) : applicationContext.getBean(tClass);
|
return beanFactory != null ? beanFactory.getBean(tClass) : applicationContext.getBean(tClass);
|
||||||
@@ -382,11 +407,9 @@ public class FeignClientFactoryBean
|
|||||||
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("The provided URL is empty. Will try picking an instance via load-balancing.");
|
if (LOG.isInfoEnabled()) {
|
||||||
}
|
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;
|
||||||
|
|||||||
+46
@@ -0,0 +1,46 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2013-2020 the original author or authors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.springframework.cloud.openfeign.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+6
-3
@@ -46,7 +46,6 @@ import org.springframework.cloud.client.loadbalancer.LoadBalancerLifecycleValida
|
|||||||
import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
|
import org.springframework.cloud.client.loadbalancer.LoadBalancerProperties;
|
||||||
import org.springframework.cloud.client.loadbalancer.ResponseData;
|
import org.springframework.cloud.client.loadbalancer.ResponseData;
|
||||||
import org.springframework.cloud.client.loadbalancer.RetryableRequestContext;
|
import org.springframework.cloud.client.loadbalancer.RetryableRequestContext;
|
||||||
import org.springframework.cloud.client.loadbalancer.RetryableStatusCodeException;
|
|
||||||
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
|
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
@@ -57,6 +56,7 @@ 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.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.util.StreamUtils;
|
||||||
|
|
||||||
import static org.springframework.cloud.openfeign.loadbalancer.LoadBalancerUtils.buildRequestData;
|
import static org.springframework.cloud.openfeign.loadbalancer.LoadBalancerUtils.buildRequestData;
|
||||||
|
|
||||||
@@ -70,7 +70,7 @@ import static org.springframework.cloud.openfeign.loadbalancer.LoadBalancerUtils
|
|||||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||||
public class RetryableFeignBlockingLoadBalancerClient implements Client {
|
public class RetryableFeignBlockingLoadBalancerClient implements Client {
|
||||||
|
|
||||||
private static final Log LOG = LogFactory.getLog(FeignBlockingLoadBalancerClient.class);
|
private static final Log LOG = LogFactory.getLog(RetryableFeignBlockingLoadBalancerClient.class);
|
||||||
|
|
||||||
private final Client delegate;
|
private final Client delegate;
|
||||||
|
|
||||||
@@ -161,8 +161,11 @@ public class RetryableFeignBlockingLoadBalancerClient implements Client {
|
|||||||
if (LOG.isDebugEnabled()) {
|
if (LOG.isDebugEnabled()) {
|
||||||
LOG.debug(String.format("Retrying on status code: %d", responseStatus));
|
LOG.debug(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, response, URI.create(request.url()));
|
throw new LoadBalancerResponseStatusCodeException(serviceId, response, byteArray,
|
||||||
|
URI.create(request.url()));
|
||||||
}
|
}
|
||||||
return response;
|
return response;
|
||||||
}, new LoadBalancedRecoveryCallback<Response, Response>() {
|
}, new LoadBalancedRecoveryCallback<Response, Response>() {
|
||||||
|
|||||||
+23
-5
@@ -38,6 +38,8 @@ import org.springframework.data.domain.Sort;
|
|||||||
*
|
*
|
||||||
* @author Pascal Büttiker
|
* @author Pascal Büttiker
|
||||||
* @author Olga Maciaszek-Sharma
|
* @author Olga Maciaszek-Sharma
|
||||||
|
* @author Pedro Mendes
|
||||||
|
* @author Nikita Konev
|
||||||
*/
|
*/
|
||||||
public class PageJacksonModule extends Module {
|
public class PageJacksonModule extends Module {
|
||||||
|
|
||||||
@@ -69,6 +71,7 @@ public class PageJacksonModule extends Module {
|
|||||||
@JsonProperty("size") int size, @JsonProperty("totalElements") @JsonAlias({ "total-elements",
|
@JsonProperty("size") int size, @JsonProperty("totalElements") @JsonAlias({ "total-elements",
|
||||||
"total_elements", "totalelements", "TotalElements" }) long totalElements,
|
"total_elements", "totalelements", "TotalElements" }) long totalElements,
|
||||||
@JsonProperty("sort") Sort sort) {
|
@JsonProperty("sort") Sort sort) {
|
||||||
|
if (size > 0) {
|
||||||
PageRequest pageRequest;
|
PageRequest pageRequest;
|
||||||
if (sort != null) {
|
if (sort != null) {
|
||||||
pageRequest = PageRequest.of(number, size, sort);
|
pageRequest = PageRequest.of(number, size, sort);
|
||||||
@@ -77,10 +80,13 @@ public class PageJacksonModule extends Module {
|
|||||||
pageRequest = PageRequest.of(number, size);
|
pageRequest = PageRequest.of(number, size);
|
||||||
}
|
}
|
||||||
delegate = new PageImpl<>(content, pageRequest, totalElements);
|
delegate = new PageImpl<>(content, pageRequest, totalElements);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
delegate = new PageImpl<>(content);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonProperty
|
@JsonIgnore
|
||||||
@Override
|
@Override
|
||||||
public int getTotalPages() {
|
public int getTotalPages() {
|
||||||
return delegate.getTotalPages();
|
return delegate.getTotalPages();
|
||||||
@@ -104,7 +110,7 @@ public class PageJacksonModule extends Module {
|
|||||||
return delegate.getSize();
|
return delegate.getSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonProperty
|
@JsonIgnore
|
||||||
@Override
|
@Override
|
||||||
public int getNumberOfElements() {
|
public int getNumberOfElements() {
|
||||||
return delegate.getNumberOfElements();
|
return delegate.getNumberOfElements();
|
||||||
@@ -128,13 +134,13 @@ public class PageJacksonModule extends Module {
|
|||||||
return delegate.getSort();
|
return delegate.getSort();
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonProperty
|
@JsonIgnore
|
||||||
@Override
|
@Override
|
||||||
public boolean isFirst() {
|
public boolean isFirst() {
|
||||||
return delegate.isFirst();
|
return delegate.isFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonProperty
|
@JsonIgnore
|
||||||
@Override
|
@Override
|
||||||
public boolean isLast() {
|
public boolean isLast() {
|
||||||
return delegate.isLast();
|
return delegate.isLast();
|
||||||
@@ -176,6 +182,18 @@ public class PageJacksonModule extends Module {
|
|||||||
return delegate.iterator();
|
return delegate.iterator();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
@Override
|
||||||
|
public Pageable getPageable() {
|
||||||
|
return delegate.getPageable();
|
||||||
|
}
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
@Override
|
||||||
|
public boolean isEmpty() {
|
||||||
|
return delegate.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+21
-8
@@ -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 {
|
||||||
@@ -95,8 +101,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 {
|
||||||
@@ -207,9 +213,16 @@ 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, MediaType.MULTIPART_RELATED)
|
return Arrays.asList(MULTIPART_FORM_DATA, MULTIPART_MIXED, 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) {
|
||||||
@@ -227,21 +240,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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-33
@@ -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;
|
||||||
@@ -82,6 +84,8 @@ import static org.springframework.core.annotation.AnnotatedElementUtils.findMerg
|
|||||||
*/
|
*/
|
||||||
public class SpringMvcContract extends Contract.BaseContract implements ResourceLoaderAware {
|
public class SpringMvcContract extends Contract.BaseContract 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";
|
||||||
@@ -169,47 +173,18 @@ public class SpringMvcContract extends Contract.BaseContract implements Resource
|
|||||||
|
|
||||||
@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, RequestMapping.class);
|
||||||
if (classAnnotation != null) {
|
if (classAnnotation != null) {
|
||||||
// Prepend path from class annotation if specified
|
LOG.error("Cannot process class: " + clz.getName()
|
||||||
if (classAnnotation.value().length > 0) {
|
+ ". @RequestMapping annotation is not allowed on @FeignClient interfaces.");
|
||||||
String pathValue = emptyToNull(classAnnotation.value()[0]);
|
throw new IllegalArgumentException("@RequestMapping annotation not allowed on @FeignClient interfaces");
|
||||||
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
|
||||||
|
|||||||
+33
@@ -16,12 +16,16 @@
|
|||||||
|
|
||||||
package org.springframework.cloud.openfeign;
|
package org.springframework.cloud.openfeign;
|
||||||
|
|
||||||
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
|
import feign.Target;
|
||||||
import org.assertj.core.api.Condition;
|
import org.assertj.core.api.Condition;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
import org.springframework.boot.autoconfigure.AutoConfigurations;
|
||||||
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||||
import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory;
|
import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory;
|
||||||
|
import org.springframework.cloud.openfeign.FeignAutoConfiguration.CircuitBreakerPresentFeignTargeterConfiguration.DefaultCircuitBreakerNameResolver;
|
||||||
import org.springframework.context.ConfigurableApplicationContext;
|
import org.springframework.context.ConfigurableApplicationContext;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
@@ -31,6 +35,7 @@ import static org.mockito.Mockito.mock;
|
|||||||
* @author Tim Peeters
|
* @author Tim Peeters
|
||||||
* @author Olga Maciaszek-Sharma
|
* @author Olga Maciaszek-Sharma
|
||||||
* @author Andrii Bohutskyi
|
* @author Andrii Bohutskyi
|
||||||
|
* @author Kwangyong Kim
|
||||||
*/
|
*/
|
||||||
class FeignAutoConfigurationTests {
|
class FeignAutoConfigurationTests {
|
||||||
|
|
||||||
@@ -50,6 +55,8 @@ class FeignAutoConfigurationTests {
|
|||||||
.withPropertyValues("feign.circuitbreaker.enabled=true").run(ctx -> {
|
.withPropertyValues("feign.circuitbreaker.enabled=true").run(ctx -> {
|
||||||
assertOnlyOneTargeterPresent(ctx, FeignCircuitBreakerTargeter.class);
|
assertOnlyOneTargeterPresent(ctx, FeignCircuitBreakerTargeter.class);
|
||||||
assertThatFeignCircuitBreakerTargeterHasGroupEnabledPropertyWithValue(ctx, false);
|
assertThatFeignCircuitBreakerTargeterHasGroupEnabledPropertyWithValue(ctx, false);
|
||||||
|
assertThatFeignCircuitBreakerTargeterHasSameCircuitBreakerNameResolver(ctx,
|
||||||
|
DefaultCircuitBreakerNameResolver.class);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,6 +70,17 @@ class FeignAutoConfigurationTests {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldInstantiateFeignCircuitBreakerTargeterWhenEnabledWithCustomCircuitBreakerNameResolver() {
|
||||||
|
runner.withBean(CircuitBreakerFactory.class, () -> mock(CircuitBreakerFactory.class))
|
||||||
|
.withBean(CircuitBreakerNameResolver.class, CustomCircuitBreakerNameResolver::new)
|
||||||
|
.withPropertyValues("feign.circuitbreaker.enabled=true").run(ctx -> {
|
||||||
|
assertOnlyOneTargeterPresent(ctx, FeignCircuitBreakerTargeter.class);
|
||||||
|
assertThatFeignCircuitBreakerTargeterHasSameCircuitBreakerNameResolver(ctx,
|
||||||
|
CustomCircuitBreakerNameResolver.class);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void assertOnlyOneTargeterPresent(ConfigurableApplicationContext ctx, Class<?> beanClass) {
|
private void assertOnlyOneTargeterPresent(ConfigurableApplicationContext ctx, Class<?> beanClass) {
|
||||||
assertThat(ctx.getBeansOfType(Targeter.class)).hasSize(1).hasValueSatisfying(new Condition<>(
|
assertThat(ctx.getBeansOfType(Targeter.class)).hasSize(1).hasValueSatisfying(new Condition<>(
|
||||||
beanClass::isInstance, String.format("Targeter should be an instance of %s", beanClass)));
|
beanClass::isInstance, String.format("Targeter should be an instance of %s", beanClass)));
|
||||||
@@ -75,4 +93,19 @@ class FeignAutoConfigurationTests {
|
|||||||
assertThat(bean).hasFieldOrPropertyWithValue("circuitBreakerGroupEnabled", expectedValue);
|
assertThat(bean).hasFieldOrPropertyWithValue("circuitBreakerGroupEnabled", expectedValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void assertThatFeignCircuitBreakerTargeterHasSameCircuitBreakerNameResolver(
|
||||||
|
ConfigurableApplicationContext ctx, Class<?> beanClass) {
|
||||||
|
final CircuitBreakerNameResolver bean = ctx.getBean(CircuitBreakerNameResolver.class);
|
||||||
|
assertThat(bean).isExactlyInstanceOf(beanClass);
|
||||||
|
}
|
||||||
|
|
||||||
|
static class CustomCircuitBreakerNameResolver implements CircuitBreakerNameResolver {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String resolveCircuitBreakerName(String feignClientName, Target<?> target, Method method) {
|
||||||
|
return feignClientName + "_" + method.getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-3
@@ -32,8 +32,7 @@ import org.springframework.context.annotation.Bean;
|
|||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.test.annotation.DirtiesContext;
|
import org.springframework.test.annotation.DirtiesContext;
|
||||||
import org.springframework.test.context.ActiveProfiles;
|
import org.springframework.test.context.ActiveProfiles;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
@@ -83,7 +82,7 @@ class FeignClientDisabledClientLevelFeaturesTests {
|
|||||||
@FeignClient(name = "bar", url = "https://bar", configuration = BarConfiguration.class)
|
@FeignClient(name = "bar", url = "https://bar", configuration = BarConfiguration.class)
|
||||||
interface BarClient {
|
interface BarClient {
|
||||||
|
|
||||||
@RequestMapping(value = "/", method = RequestMethod.GET)
|
@GetMapping("/")
|
||||||
String get();
|
String get();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-3
@@ -32,8 +32,7 @@ import org.springframework.context.annotation.Bean;
|
|||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.test.annotation.DirtiesContext;
|
import org.springframework.test.annotation.DirtiesContext;
|
||||||
import org.springframework.test.context.ActiveProfiles;
|
import org.springframework.test.context.ActiveProfiles;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
@@ -82,7 +81,7 @@ class FeignClientDisabledFeaturesTests {
|
|||||||
@FeignClient(name = "bar", url = "https://bar", configuration = BarConfiguration.class)
|
@FeignClient(name = "bar", url = "https://bar", configuration = BarConfiguration.class)
|
||||||
interface BarClient {
|
interface BarClient {
|
||||||
|
|
||||||
@RequestMapping(value = "/", method = RequestMethod.GET)
|
@GetMapping("/")
|
||||||
String get();
|
String get();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-3
@@ -37,8 +37,7 @@ import org.springframework.context.annotation.Bean;
|
|||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.test.annotation.DirtiesContext;
|
import org.springframework.test.annotation.DirtiesContext;
|
||||||
import org.springframework.test.util.ReflectionTestUtils;
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
@@ -133,7 +132,7 @@ public class FeignClientErrorDecoderTests {
|
|||||||
@FeignClient(name = "bar", url = "http://bar", configuration = BarConfiguration.class)
|
@FeignClient(name = "bar", url = "http://bar", configuration = BarConfiguration.class)
|
||||||
interface BarClient {
|
interface BarClient {
|
||||||
|
|
||||||
@RequestMapping(value = "/", method = RequestMethod.GET)
|
@GetMapping("/")
|
||||||
String get();
|
String get();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-3
@@ -39,10 +39,9 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext
|
|||||||
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.test.util.ReflectionTestUtils;
|
import org.springframework.test.util.ReflectionTestUtils;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.springframework.web.bind.annotation.RequestMethod.GET;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Spencer Gibb
|
* @author Spencer Gibb
|
||||||
@@ -90,7 +89,7 @@ public class FeignClientFactoryTests {
|
|||||||
|
|
||||||
interface TestType {
|
interface TestType {
|
||||||
|
|
||||||
@RequestMapping(value = "/", method = GET)
|
@GetMapping("/")
|
||||||
String hello();
|
String hello();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-5
@@ -66,8 +66,6 @@ import org.springframework.test.util.ReflectionTestUtils;
|
|||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
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.RequestMethod;
|
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
@@ -295,8 +293,7 @@ public class FeignClientUsingPropertiesTests {
|
|||||||
|
|
||||||
protected interface FormClient {
|
protected interface FormClient {
|
||||||
|
|
||||||
@RequestMapping(value = "/form", method = RequestMethod.POST,
|
@PostMapping(value = "/form", consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
||||||
consumes = MediaType.APPLICATION_FORM_URLENCODED_VALUE)
|
|
||||||
String form(Map<String, String> form);
|
String form(Map<String, String> form);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -328,7 +325,7 @@ public class FeignClientUsingPropertiesTests {
|
|||||||
@Import(NoSecurityConfiguration.class)
|
@Import(NoSecurityConfiguration.class)
|
||||||
protected static class Application {
|
protected static class Application {
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/foo")
|
@GetMapping("/foo")
|
||||||
public String foo(HttpServletRequest request) throws IllegalAccessException {
|
public String foo(HttpServletRequest request) throws IllegalAccessException {
|
||||||
if ("Foo".equals(request.getHeader("Foo")) && "Bar".equals(request.getHeader("Bar"))) {
|
if ("Foo".equals(request.getHeader("Foo")) && "Bar".equals(request.getHeader("Bar"))) {
|
||||||
return "OK";
|
return "OK";
|
||||||
|
|||||||
+3
-4
@@ -25,8 +25,7 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
|||||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.mock.env.MockEnvironment;
|
import org.springframework.mock.env.MockEnvironment;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.assertj.core.api.Assertions.assertThatCode;
|
import static org.assertj.core.api.Assertions.assertThatCode;
|
||||||
@@ -105,7 +104,7 @@ public class FeignClientsRegistrarTests {
|
|||||||
@FeignClient(name = "fallbackTestClient", url = "http://localhost:8080/", fallback = FallbackClient.class)
|
@FeignClient(name = "fallbackTestClient", url = "http://localhost:8080/", fallback = FallbackClient.class)
|
||||||
protected interface FallbackClient {
|
protected interface FallbackClient {
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/hello")
|
@GetMapping("/hello")
|
||||||
String fallbackTest();
|
String fallbackTest();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -114,7 +113,7 @@ public class FeignClientsRegistrarTests {
|
|||||||
fallbackFactory = FallbackFactoryClient.class)
|
fallbackFactory = FallbackFactoryClient.class)
|
||||||
protected interface FallbackFactoryClient {
|
protected interface FallbackFactoryClient {
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/hello")
|
@GetMapping("/hello")
|
||||||
String fallbackFactoryTest();
|
String fallbackFactoryTest();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-7
@@ -37,8 +37,7 @@ import org.springframework.context.annotation.Import;
|
|||||||
import org.springframework.test.annotation.DirtiesContext;
|
import org.springframework.test.annotation.DirtiesContext;
|
||||||
import org.springframework.util.ReflectionUtils;
|
import org.springframework.util.ReflectionUtils;
|
||||||
import org.springframework.util.SocketUtils;
|
import org.springframework.util.SocketUtils;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
@@ -102,7 +101,7 @@ class FeignHttpClientUrlTests {
|
|||||||
@FeignClient(name = "localappurl", url = "http://localhost:${server.port}/")
|
@FeignClient(name = "localappurl", url = "http://localhost:${server.port}/")
|
||||||
protected interface UrlClient {
|
protected interface UrlClient {
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/hello")
|
@GetMapping("/hello")
|
||||||
Hello getHello();
|
Hello getHello();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -110,7 +109,7 @@ class FeignHttpClientUrlTests {
|
|||||||
@FeignClient(name = "beanappurl", url = "#{SERVER_URL}path")
|
@FeignClient(name = "beanappurl", url = "#{SERVER_URL}path")
|
||||||
protected interface BeanUrlClient {
|
protected interface BeanUrlClient {
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/hello")
|
@GetMapping("/hello")
|
||||||
Hello getHello();
|
Hello getHello();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -118,7 +117,7 @@ class FeignHttpClientUrlTests {
|
|||||||
@FeignClient(name = "beanappurlnoprotocol", url = "#{SERVER_URL_NO_PROTOCOL}path")
|
@FeignClient(name = "beanappurlnoprotocol", url = "#{SERVER_URL_NO_PROTOCOL}path")
|
||||||
protected interface BeanUrlClientNoProtocol {
|
protected interface BeanUrlClientNoProtocol {
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/hello")
|
@GetMapping("/hello")
|
||||||
Hello getHello();
|
Hello getHello();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -130,12 +129,12 @@ class FeignHttpClientUrlTests {
|
|||||||
@Import(NoSecurityConfiguration.class)
|
@Import(NoSecurityConfiguration.class)
|
||||||
protected static class TestConfig {
|
protected static class TestConfig {
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/hello")
|
@GetMapping("/hello")
|
||||||
public Hello getHello() {
|
public Hello getHello() {
|
||||||
return new Hello("hello world 1");
|
return new Hello("hello world 1");
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/path/hello")
|
@GetMapping("/path/hello")
|
||||||
public Hello getHelloWithPath() {
|
public Hello getHelloWithPath() {
|
||||||
return getHello();
|
return getHello();
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-5
@@ -38,8 +38,6 @@ import org.springframework.test.annotation.DirtiesContext;
|
|||||||
import org.springframework.util.ReflectionUtils;
|
import org.springframework.util.ReflectionUtils;
|
||||||
import org.springframework.util.SocketUtils;
|
import org.springframework.util.SocketUtils;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
@@ -104,7 +102,7 @@ class FeignHttpClientUrlTestsWithRetryableLoadBalancer {
|
|||||||
@FeignClient(name = "localappurl", url = "http://localhost:${server.port}/")
|
@FeignClient(name = "localappurl", url = "http://localhost:${server.port}/")
|
||||||
protected interface UrlClient {
|
protected interface UrlClient {
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/hello")
|
@GetMapping("/hello")
|
||||||
Hello getHello();
|
Hello getHello();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -112,7 +110,7 @@ class FeignHttpClientUrlTestsWithRetryableLoadBalancer {
|
|||||||
@FeignClient(name = "beanappurl", url = "#{SERVER_URL}path")
|
@FeignClient(name = "beanappurl", url = "#{SERVER_URL}path")
|
||||||
protected interface BeanUrlClient {
|
protected interface BeanUrlClient {
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/hello")
|
@GetMapping("/hello")
|
||||||
Hello getHello();
|
Hello getHello();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -120,7 +118,7 @@ class FeignHttpClientUrlTestsWithRetryableLoadBalancer {
|
|||||||
@FeignClient(name = "beanappurlnoprotocol", url = "#{SERVER_URL_NO_PROTOCOL}path")
|
@FeignClient(name = "beanappurlnoprotocol", url = "#{SERVER_URL_NO_PROTOCOL}path")
|
||||||
protected interface BeanUrlClientNoProtocol {
|
protected interface BeanUrlClientNoProtocol {
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/hello")
|
@GetMapping("/hello")
|
||||||
Hello getHello();
|
Hello getHello();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-8
@@ -39,8 +39,6 @@ import org.springframework.http.ResponseEntity;
|
|||||||
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.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
@@ -154,22 +152,22 @@ public class SpringDecoderTests extends FeignClientFactoryBean {
|
|||||||
|
|
||||||
protected interface TestClient {
|
protected interface TestClient {
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/helloresponse")
|
@GetMapping("/helloresponse")
|
||||||
ResponseEntity<Hello> getHelloResponse();
|
ResponseEntity<Hello> getHelloResponse();
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/hellovoid")
|
@GetMapping("/hellovoid")
|
||||||
ResponseEntity<Void> getHelloVoid();
|
ResponseEntity<Void> getHelloVoid();
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/hello")
|
@GetMapping("/hello")
|
||||||
Hello getHello();
|
Hello getHello();
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/hellos")
|
@GetMapping("/hellos")
|
||||||
List<Hello> getHellos();
|
List<Hello> getHellos();
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/hellostrings")
|
@GetMapping("/hellostrings")
|
||||||
List<String> getHelloStrings();
|
List<String> getHelloStrings();
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/hellonotfound")
|
@GetMapping("/hellonotfound")
|
||||||
ResponseEntity<String> getNotFound();
|
ResponseEntity<String> getNotFound();
|
||||||
|
|
||||||
@GetMapping("/helloWildcard")
|
@GetMapping("/helloWildcard")
|
||||||
|
|||||||
+2
-3
@@ -39,8 +39,7 @@ import org.springframework.context.annotation.Configuration;
|
|||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
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.RequestMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
@@ -122,7 +121,7 @@ public class BeansFeignClientTests {
|
|||||||
return feignClientBuilder.forType(TestClient.class, "builderapp").build();
|
return feignClientBuilder.forType(TestClient.class, "builderapp").build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/hello")
|
@GetMapping("/hello")
|
||||||
public Hello getHello() {
|
public Hello getHello() {
|
||||||
return new Hello("hello world 1");
|
return new Hello("hello world 1");
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-3
@@ -19,14 +19,13 @@ package org.springframework.cloud.openfeign.beans;
|
|||||||
import org.springframework.cloud.openfeign.FeignClient;
|
import org.springframework.cloud.openfeign.FeignClient;
|
||||||
import org.springframework.cloud.openfeign.beans.BeansFeignClientTests.Hello;
|
import org.springframework.cloud.openfeign.beans.BeansFeignClientTests.Hello;
|
||||||
import org.springframework.context.annotation.Primary;
|
import org.springframework.context.annotation.Primary;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
|
||||||
|
|
||||||
@Primary
|
@Primary
|
||||||
@FeignClient("localapp")
|
@FeignClient("localapp")
|
||||||
public interface TestClient {
|
public interface TestClient {
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/hello")
|
@GetMapping("/hello")
|
||||||
Hello getHello();
|
Hello getHello();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-3
@@ -18,13 +18,12 @@ package org.springframework.cloud.openfeign.beans.extra;
|
|||||||
|
|
||||||
import org.springframework.cloud.openfeign.FeignClient;
|
import org.springframework.cloud.openfeign.FeignClient;
|
||||||
import org.springframework.cloud.openfeign.beans.BeansFeignClientTests.Hello;
|
import org.springframework.cloud.openfeign.beans.BeansFeignClientTests.Hello;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
|
||||||
|
|
||||||
@FeignClient(value = "otherapp", qualifier = "uniquequalifier")
|
@FeignClient(value = "otherapp", qualifier = "uniquequalifier")
|
||||||
public interface TestClient {
|
public interface TestClient {
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/hello")
|
@GetMapping("/hello")
|
||||||
Hello getHello();
|
Hello getHello();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-6
@@ -45,8 +45,7 @@ import org.springframework.stereotype.Component;
|
|||||||
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.util.SocketUtils;
|
import org.springframework.util.SocketUtils;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
@@ -115,10 +114,10 @@ public class CircuitBreakerTests {
|
|||||||
@FeignClient(name = "test", url = "http://localhost:${server.port}/", fallback = Fallback.class)
|
@FeignClient(name = "test", url = "http://localhost:${server.port}/", fallback = Fallback.class)
|
||||||
protected interface TestClient {
|
protected interface TestClient {
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/hello")
|
@GetMapping("/hello")
|
||||||
Hello getHello();
|
Hello getHello();
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/hellonotfound")
|
@GetMapping("/hellonotfound")
|
||||||
String getException();
|
String getException();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -142,10 +141,10 @@ public class CircuitBreakerTests {
|
|||||||
fallbackFactory = TestFallbackFactory.class)
|
fallbackFactory = TestFallbackFactory.class)
|
||||||
protected interface TestClientWithFactory {
|
protected interface TestClientWithFactory {
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/hello")
|
@GetMapping("/hello")
|
||||||
Hello getHello();
|
Hello getHello();
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/hellonotfound")
|
@GetMapping("/hellonotfound")
|
||||||
String getException();
|
String getException();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-4
@@ -40,8 +40,7 @@ import org.springframework.context.annotation.Configuration;
|
|||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.test.annotation.DirtiesContext;
|
import org.springframework.test.annotation.DirtiesContext;
|
||||||
import org.springframework.util.SocketUtils;
|
import org.springframework.util.SocketUtils;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
@@ -97,10 +96,10 @@ public class CircuitBreakerWithNoFallbackTests {
|
|||||||
@FeignClient(name = "test", url = "http://localhost:${server.port}/")
|
@FeignClient(name = "test", url = "http://localhost:${server.port}/")
|
||||||
protected interface CircuitBreakerTestClient {
|
protected interface CircuitBreakerTestClient {
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/hello")
|
@GetMapping("/hello")
|
||||||
Hello getHello();
|
Hello getHello();
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/hellonotfound")
|
@GetMapping("/hellonotfound")
|
||||||
String getException();
|
String getException();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-9
@@ -24,9 +24,9 @@ import org.springframework.cloud.openfeign.encoding.app.domain.Invoice;
|
|||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
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.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Simple Feign client for retrieving the invoice list.
|
* Simple Feign client for retrieving the invoice list.
|
||||||
@@ -37,23 +37,23 @@ import org.springframework.web.bind.annotation.RequestMethod;
|
|||||||
@FeignClient("local")
|
@FeignClient("local")
|
||||||
public interface InvoiceClient {
|
public interface InvoiceClient {
|
||||||
|
|
||||||
@RequestMapping(value = "invoicesPaged", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
|
@GetMapping(value = "invoicesPaged", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
ResponseEntity<Page<Invoice>> getInvoicesPaged(org.springframework.data.domain.Pageable pageable);
|
ResponseEntity<Page<Invoice>> getInvoicesPaged(org.springframework.data.domain.Pageable pageable);
|
||||||
|
|
||||||
@RequestMapping(value = "invoicesPagedWithBody", method = RequestMethod.POST,
|
@PostMapping(value = "invoicesPagedWithBody", consumes = MediaType.APPLICATION_JSON_VALUE,
|
||||||
consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
ResponseEntity<Page<Invoice>> getInvoicesPagedWithBody(
|
ResponseEntity<Page<Invoice>> getInvoicesPagedWithBody(
|
||||||
@SpringQueryMap org.springframework.data.domain.Pageable pageable, @RequestBody String titlePrefix);
|
@SpringQueryMap org.springframework.data.domain.Pageable pageable, @RequestBody String titlePrefix);
|
||||||
|
|
||||||
@RequestMapping(value = "invoicesSortedWithBody", method = RequestMethod.POST,
|
@PostMapping(value = "invoicesSortedWithBody", consumes = MediaType.APPLICATION_JSON_VALUE,
|
||||||
consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
ResponseEntity<Page<Invoice>> getInvoicesSortedWithBody(@SpringQueryMap org.springframework.data.domain.Sort sort,
|
ResponseEntity<Page<Invoice>> getInvoicesSortedWithBody(@SpringQueryMap org.springframework.data.domain.Sort sort,
|
||||||
@RequestBody String titlePrefix);
|
@RequestBody String titlePrefix);
|
||||||
|
|
||||||
@RequestMapping(value = "invoices", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
|
@GetMapping(value = "invoices", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
ResponseEntity<List<Invoice>> getInvoices();
|
ResponseEntity<List<Invoice>> getInvoices();
|
||||||
|
|
||||||
@RequestMapping(value = "invoices", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE,
|
@PostMapping(value = "invoices", consumes = MediaType.APPLICATION_JSON_VALUE,
|
||||||
produces = MediaType.APPLICATION_JSON_VALUE)
|
produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
ResponseEntity<List<Invoice>> saveInvoices(List<Invoice> invoices);
|
ResponseEntity<List<Invoice>> saveInvoices(List<Invoice> invoices);
|
||||||
|
|
||||||
|
|||||||
+9
-9
@@ -28,9 +28,9 @@ import org.springframework.data.domain.PageImpl;
|
|||||||
import org.springframework.data.domain.PageRequest;
|
import org.springframework.data.domain.PageRequest;
|
||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
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.RequestMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -42,28 +42,28 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
@RestController
|
@RestController
|
||||||
public class InvoiceResource {
|
public class InvoiceResource {
|
||||||
|
|
||||||
@RequestMapping(value = "invoices", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
|
@GetMapping(value = "invoices", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
public ResponseEntity<List<Invoice>> getInvoices() {
|
public ResponseEntity<List<Invoice>> getInvoices() {
|
||||||
|
|
||||||
return ResponseEntity.ok(createInvoiceList(null, 100, null));
|
return ResponseEntity.ok(createInvoiceList(null, 100, null));
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(value = "invoices", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE,
|
@PostMapping(value = "invoices", consumes = MediaType.APPLICATION_JSON_VALUE,
|
||||||
produces = MediaType.APPLICATION_JSON_VALUE)
|
produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
ResponseEntity<List<Invoice>> saveInvoices(@RequestBody List<Invoice> invoices) {
|
ResponseEntity<List<Invoice>> saveInvoices(@RequestBody List<Invoice> invoices) {
|
||||||
|
|
||||||
return ResponseEntity.ok(invoices);
|
return ResponseEntity.ok(invoices);
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(value = "invoicesPaged", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
|
@GetMapping(value = "invoicesPaged", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
public ResponseEntity<Page<Invoice>> getInvoicesPaged(org.springframework.data.domain.Pageable pageable) {
|
public ResponseEntity<Page<Invoice>> getInvoicesPaged(org.springframework.data.domain.Pageable pageable) {
|
||||||
Page<Invoice> page = new PageImpl<>(createInvoiceList(null, pageable.getPageSize(), pageable.getSort()),
|
Page<Invoice> page = new PageImpl<>(createInvoiceList(null, pageable.getPageSize(), pageable.getSort()),
|
||||||
pageable, 100);
|
pageable, 100);
|
||||||
return ResponseEntity.ok(page);
|
return ResponseEntity.ok(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(value = "invoicesPagedWithBody", method = RequestMethod.POST,
|
@PostMapping(value = "invoicesPagedWithBody", consumes = MediaType.APPLICATION_JSON_VALUE,
|
||||||
consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
public ResponseEntity<Page<Invoice>> getInvoicesPagedWithBody(org.springframework.data.domain.Pageable pageable,
|
public ResponseEntity<Page<Invoice>> getInvoicesPagedWithBody(org.springframework.data.domain.Pageable pageable,
|
||||||
@RequestBody String titlePrefix) {
|
@RequestBody String titlePrefix) {
|
||||||
Page<Invoice> page = new PageImpl<>(createInvoiceList(titlePrefix, pageable.getPageSize(), pageable.getSort()),
|
Page<Invoice> page = new PageImpl<>(createInvoiceList(titlePrefix, pageable.getPageSize(), pageable.getSort()),
|
||||||
@@ -71,8 +71,8 @@ public class InvoiceResource {
|
|||||||
return ResponseEntity.ok(page);
|
return ResponseEntity.ok(page);
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(value = "invoicesSortedWithBody", method = RequestMethod.POST,
|
@PostMapping(value = "invoicesSortedWithBody", consumes = MediaType.APPLICATION_JSON_VALUE,
|
||||||
consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
|
produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
public ResponseEntity<Page<Invoice>> getInvoicesSortedWithBody(org.springframework.data.domain.Sort sort,
|
public ResponseEntity<Page<Invoice>> getInvoicesSortedWithBody(org.springframework.data.domain.Sort sort,
|
||||||
@RequestBody String titlePrefix) {
|
@RequestBody String titlePrefix) {
|
||||||
Page<Invoice> page = new PageImpl<>(createInvoiceList(titlePrefix, 100, sort), PageRequest.of(0, 100, sort),
|
Page<Invoice> page = new PageImpl<>(createInvoiceList(titlePrefix, 100, sort), PageRequest.of(0, 100, sort),
|
||||||
|
|||||||
+5
-6
@@ -28,8 +28,7 @@ import org.springframework.cloud.openfeign.FeignClient;
|
|||||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
@@ -74,7 +73,7 @@ public class FeignClientValidationTests {
|
|||||||
@FeignClient(name = "bar")
|
@FeignClient(name = "bar")
|
||||||
interface Client {
|
interface Client {
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/")
|
@GetMapping("/")
|
||||||
String get();
|
String get();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -90,7 +89,7 @@ public class FeignClientValidationTests {
|
|||||||
@FeignClient(contextId = "foo", name = "bar")
|
@FeignClient(contextId = "foo", name = "bar")
|
||||||
interface FooClient {
|
interface FooClient {
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/")
|
@GetMapping("/")
|
||||||
String get();
|
String get();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -98,7 +97,7 @@ public class FeignClientValidationTests {
|
|||||||
@FeignClient(name = "bar")
|
@FeignClient(name = "bar")
|
||||||
interface BarClient {
|
interface BarClient {
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/")
|
@GetMapping("/")
|
||||||
String get();
|
String get();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -113,7 +112,7 @@ public class FeignClientValidationTests {
|
|||||||
@FeignClient("foo_bar")
|
@FeignClient("foo_bar")
|
||||||
interface Client {
|
interface Client {
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/")
|
@GetMapping("/")
|
||||||
String get();
|
String get();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+27
@@ -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;
|
||||||
@@ -29,6 +32,7 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
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;
|
||||||
@@ -117,6 +121,13 @@ 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 +159,22 @@ class RetryableFeignBlockingLoadBalancerClientTests {
|
|||||||
verify(delegate, times(2)).execute(any(), any());
|
verify(delegate, times(2)).execute(any(), any());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void shouldExposeResponseBodyOnRetry() throws IOException {
|
||||||
|
properties.getRetry().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(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();
|
||||||
|
|||||||
+44
@@ -16,13 +16,18 @@
|
|||||||
|
|
||||||
package org.springframework.cloud.openfeign.support;
|
package org.springframework.cloud.openfeign.support;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import org.junit.jupiter.api.BeforeAll;
|
import org.junit.jupiter.api.BeforeAll;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.params.ParameterizedTest;
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
import org.junit.jupiter.params.provider.ValueSource;
|
import org.junit.jupiter.params.provider.ValueSource;
|
||||||
|
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.PageImpl;
|
||||||
|
import org.springframework.data.domain.PageRequest;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
@@ -31,6 +36,8 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||||||
*
|
*
|
||||||
* @author Ruben Vervaeke
|
* @author Ruben Vervaeke
|
||||||
* @author Olga Maciaszek-Sharma
|
* @author Olga Maciaszek-Sharma
|
||||||
|
* @author Pedro Mendes
|
||||||
|
* @author Nikita Konev
|
||||||
*/
|
*/
|
||||||
public class PageJacksonModuleTests {
|
public class PageJacksonModuleTests {
|
||||||
|
|
||||||
@@ -40,6 +47,7 @@ public class PageJacksonModuleTests {
|
|||||||
public static void initialize() {
|
public static void initialize() {
|
||||||
objectMapper = new ObjectMapper();
|
objectMapper = new ObjectMapper();
|
||||||
objectMapper.registerModule(new PageJacksonModule());
|
objectMapper.registerModule(new PageJacksonModule());
|
||||||
|
objectMapper.registerModule(new SortJacksonModule());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@@ -58,4 +66,40 @@ public class PageJacksonModuleTests {
|
|||||||
assertThat(result.getPageable().getPageNumber()).isEqualTo(1);
|
assertThat(result.getPageable().getPageNumber()).isEqualTo(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void serializeAndDeserializeEmpty() throws JsonProcessingException {
|
||||||
|
// Given
|
||||||
|
PageImpl<Object> objects = new PageImpl<>(new ArrayList<>());
|
||||||
|
String pageJson = objectMapper.writeValueAsString(objects);
|
||||||
|
// When
|
||||||
|
Page<?> result = objectMapper.readValue(pageJson, Page.class);
|
||||||
|
// Then
|
||||||
|
assertThat(result).isNotNull();
|
||||||
|
assertThat(result.getTotalElements()).isEqualTo(0);
|
||||||
|
assertThat(result.getContent()).hasSize(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void serializeAndDeserializeFilledMultiple() throws JsonProcessingException {
|
||||||
|
// Given
|
||||||
|
ArrayList<Object> strings0 = new ArrayList<>();
|
||||||
|
strings0.add("first element");
|
||||||
|
strings0.add("second element");
|
||||||
|
PageImpl<Object> objects = new PageImpl<>(strings0, PageRequest.of(6, 2), 100);
|
||||||
|
assertThat(objects.getContent()).hasSize(2);
|
||||||
|
assertThat(objects.getPageable().getPageSize()).isEqualTo(2);
|
||||||
|
|
||||||
|
String pageJson = objectMapper.writeValueAsString(objects);
|
||||||
|
// When
|
||||||
|
Page<?> result = objectMapper.readValue(pageJson, Page.class);
|
||||||
|
// Then
|
||||||
|
assertThat(result).isNotNull();
|
||||||
|
assertThat(result.getTotalElements()).isEqualTo(100);
|
||||||
|
assertThat(result.getContent()).hasSize(2);
|
||||||
|
assertThat(result.getContent().get(0)).isEqualTo("first element");
|
||||||
|
assertThat(result.getContent().get(1)).isEqualTo("second element");
|
||||||
|
assertThat(result.getPageable().getPageSize()).isEqualTo(2);
|
||||||
|
assertThat(result.getPageable().getPageNumber()).isEqualTo(6);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+13
@@ -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, webEnvironment = WebEnvironment.RANDOM_PORT,
|
@SpringBootTest(classes = SpringEncoderTests.Application.class, webEnvironment = WebEnvironment.RANDOM_PORT,
|
||||||
@@ -179,6 +181,17 @@ public class SpringEncoderTests {
|
|||||||
assertThat(new String(request.requestBody().asBytes())).as("Body content cannot be decoded").contains("hi");
|
assertThat(new String(request.requestBody().asBytes())).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);
|
||||||
|
|||||||
+43
-70
@@ -50,6 +50,7 @@ import org.springframework.web.bind.annotation.GetMapping;
|
|||||||
import org.springframework.web.bind.annotation.MatrixVariable;
|
import org.springframework.web.bind.annotation.MatrixVariable;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PutMapping;
|
||||||
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;
|
||||||
@@ -62,6 +63,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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -168,16 +170,12 @@ public class SpringMvcContractTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testProcessAnnotations_Class_AnnotationsGetSpecificTest() throws Exception {
|
public void testProcessAnnotations_Class_Annotations_RequestMapping() {
|
||||||
Method method = TestTemplate_Class_Annotations.class.getDeclaredMethod("getSpecificTest", String.class,
|
assertThatIllegalArgumentException().isThrownBy(() -> {
|
||||||
|
Method method = TestTemplate_Class_RequestMapping.class.getDeclaredMethod("getSpecificTest", String.class,
|
||||||
String.class);
|
String.class);
|
||||||
MethodMetadata data = contract.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
contract.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
|
||||||
@@ -185,25 +183,13 @@ public class SpringMvcContractTests {
|
|||||||
Method method = TestTemplate_Class_Annotations.class.getDeclaredMethod("getAllTests", String.class);
|
Method method = TestTemplate_Class_Annotations.class.getDeclaredMethod("getAllTests", String.class);
|
||||||
MethodMetadata data = contract.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
MethodMetadata data = contract.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");
|
||||||
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", String.class);
|
Method extendedMethod = TestTemplate_Extended.class.getMethod("getAllTests", String.class);
|
||||||
@@ -220,22 +206,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", TestObject.class);
|
Method method = TestTemplate_Simple.class.getDeclaredMethod("postTest", TestObject.class);
|
||||||
@@ -266,7 +236,7 @@ public class SpringMvcContractTests {
|
|||||||
Integer.class);
|
Integer.class);
|
||||||
MethodMetadata data = contract.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
MethodMetadata data = contract.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||||
|
|
||||||
assertThat(data.template().url()).isEqualTo("/advanced/test/{id}?amount=" + "{amount}");
|
assertThat(data.template().url()).isEqualTo("/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);
|
||||||
@@ -296,7 +266,7 @@ public class SpringMvcContractTests {
|
|||||||
Integer.class);
|
Integer.class);
|
||||||
MethodMetadata data = contract.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
MethodMetadata data = contract.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||||
|
|
||||||
assertThat(data.template().url()).isEqualTo("/advanced/test/{id}?amount=" + "{amount}");
|
assertThat(data.template().url()).isEqualTo("/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);
|
||||||
@@ -315,7 +285,7 @@ public class SpringMvcContractTests {
|
|||||||
Method method = TestTemplate_Advanced.class.getDeclaredMethod("getTest2", String.class, Integer.class);
|
Method method = TestTemplate_Advanced.class.getDeclaredMethod("getTest2", String.class, Integer.class);
|
||||||
MethodMetadata data = contract.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
MethodMetadata data = contract.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||||
|
|
||||||
assertThat(data.template().url()).isEqualTo("/advanced/test2?amount=" + "{amount}");
|
assertThat(data.template().url()).isEqualTo("/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);
|
||||||
@@ -367,7 +337,7 @@ public class SpringMvcContractTests {
|
|||||||
Method method = TestTemplate_Advanced.class.getDeclaredMethod("getTest");
|
Method method = TestTemplate_Advanced.class.getDeclaredMethod("getTest");
|
||||||
MethodMetadata data = contract.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
MethodMetadata data = contract.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);
|
||||||
@@ -459,7 +429,7 @@ public class SpringMvcContractTests {
|
|||||||
|
|
||||||
MethodMetadata data = contract.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
MethodMetadata data = contract.parseAndValidateMetadata(method.getDeclaringClass(), method);
|
||||||
|
|
||||||
assertThat(data.template().url()).isEqualTo("/advanced/testfallback/{id}?amount=" + "{amount}");
|
assertThat(data.template().url()).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);
|
||||||
@@ -587,13 +557,13 @@ public class SpringMvcContractTests {
|
|||||||
@RequestMapping(value = "/test/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
|
@RequestMapping(value = "/test/{id}", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
ResponseEntity<TestObject> getTest(@PathVariable("id") String id);
|
ResponseEntity<TestObject> getTest(@PathVariable("id") String id);
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
|
@GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
TestObject getTest();
|
TestObject getTest();
|
||||||
|
|
||||||
@GetMapping(value = "/test/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
|
@GetMapping(value = "/test/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
ResponseEntity<TestObject> getMappingTest(@PathVariable("id") String id);
|
ResponseEntity<TestObject> getMappingTest(@PathVariable("id") String id);
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
|
@PostMapping(produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
TestObject postTest(@RequestBody TestObject object);
|
TestObject postTest(@RequestBody TestObject object);
|
||||||
|
|
||||||
@PostMapping(produces = MediaType.APPLICATION_JSON_VALUE)
|
@PostMapping(produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
@@ -602,11 +572,18 @@ public class SpringMvcContractTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping("/prepend/{classId}")
|
@RequestMapping("/prepend/{classId}")
|
||||||
public interface TestTemplate_Class_Annotations {
|
public interface TestTemplate_Class_RequestMapping {
|
||||||
|
|
||||||
@RequestMapping(value = "/test/{testId}", method = RequestMethod.GET)
|
@RequestMapping(value = "/test/{testId}", method = RequestMethod.GET)
|
||||||
TestObject getSpecificTest(@PathVariable("classId") String classId, @PathVariable("testId") String testId);
|
TestObject getSpecificTest(@PathVariable("classId") String classId, @PathVariable("testId") String testId);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface TestTemplate_Class_Annotations {
|
||||||
|
|
||||||
|
@GetMapping("/test/{testId}")
|
||||||
|
TestObject getSpecificTest(@PathVariable("classId") String classId, @PathVariable("testId") String testId);
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET)
|
@RequestMapping(method = RequestMethod.GET)
|
||||||
TestObject getAllTests(@PathVariable("classId") String classId);
|
TestObject getAllTests(@PathVariable("classId") String classId);
|
||||||
|
|
||||||
@@ -618,47 +595,46 @@ public class SpringMvcContractTests {
|
|||||||
|
|
||||||
public interface TestTemplate_Headers {
|
public interface TestTemplate_Headers {
|
||||||
|
|
||||||
@RequestMapping(value = "/test/{id}", method = RequestMethod.GET, headers = "X-Foo=bar")
|
@GetMapping(value = "/test/{id}", headers = "X-Foo=bar")
|
||||||
ResponseEntity<TestObject> getTest(@PathVariable("id") String id);
|
ResponseEntity<TestObject> getTest(@PathVariable("id") String id);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface TestTemplate_HeadersWithoutValues {
|
public interface TestTemplate_HeadersWithoutValues {
|
||||||
|
|
||||||
@RequestMapping(value = "/test/{id}", method = RequestMethod.GET,
|
@GetMapping(value = "/test/{id}", headers = { "X-Foo", "!X-Bar", "X-Baz!=fooBar" })
|
||||||
headers = { "X-Foo", "!X-Bar", "X-Baz!=fooBar" })
|
|
||||||
ResponseEntity<TestObject> getTest(@PathVariable("id") String id);
|
ResponseEntity<TestObject> getTest(@PathVariable("id") String id);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface TestTemplate_ListParams {
|
public interface TestTemplate_ListParams {
|
||||||
|
|
||||||
@RequestMapping(value = "/test", method = RequestMethod.GET)
|
@GetMapping("/test")
|
||||||
ResponseEntity<TestObject> getTest(@RequestParam("id") List<String> id);
|
ResponseEntity<TestObject> getTest(@RequestParam("id") List<String> id);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface TestTemplate_ListParamsWithoutName {
|
public interface TestTemplate_ListParamsWithoutName {
|
||||||
|
|
||||||
@RequestMapping(value = "/test", method = RequestMethod.GET)
|
@GetMapping("/test")
|
||||||
ResponseEntity<TestObject> getTest(@RequestParam List<String> id);
|
ResponseEntity<TestObject> getTest(@RequestParam List<String> id);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface TestTemplate_MapParams {
|
public interface TestTemplate_MapParams {
|
||||||
|
|
||||||
@RequestMapping(value = "/test", method = RequestMethod.GET)
|
@GetMapping("/test")
|
||||||
ResponseEntity<TestObject> getTest(@RequestParam Map<String, String> params);
|
ResponseEntity<TestObject> getTest(@RequestParam Map<String, String> params);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface TestTemplate_HeaderMap {
|
public interface TestTemplate_HeaderMap {
|
||||||
|
|
||||||
@RequestMapping(path = "/headerMap")
|
@GetMapping("/headerMap")
|
||||||
String headerMap(@RequestHeader MultiValueMap<String, String> headerMap,
|
String headerMap(@RequestHeader MultiValueMap<String, String> headerMap,
|
||||||
@RequestHeader(name = "aHeader") String aHeader);
|
@RequestHeader(name = "aHeader") String aHeader);
|
||||||
|
|
||||||
@RequestMapping(path = "/headerMapMoreThanOnce")
|
@GetMapping("/headerMapMoreThanOnce")
|
||||||
String headerMapMoreThanOnce(@RequestHeader MultiValueMap<String, String> headerMap1,
|
String headerMapMoreThanOnce(@RequestHeader MultiValueMap<String, String> headerMap1,
|
||||||
@RequestHeader MultiValueMap<String, String> headerMap2);
|
@RequestHeader MultiValueMap<String, String> headerMap2);
|
||||||
|
|
||||||
@@ -666,42 +642,40 @@ public class SpringMvcContractTests {
|
|||||||
|
|
||||||
public interface TestTemplate_QueryMap {
|
public interface TestTemplate_QueryMap {
|
||||||
|
|
||||||
@RequestMapping(path = "/queryMap")
|
@GetMapping("/queryMap")
|
||||||
String queryMap(@RequestParam MultiValueMap<String, String> queryMap,
|
String queryMap(@RequestParam MultiValueMap<String, String> queryMap,
|
||||||
@RequestParam(name = "aParam") String aParam);
|
@RequestParam(name = "aParam") String aParam);
|
||||||
|
|
||||||
@RequestMapping(path = "/queryMapMoreThanOnce")
|
@GetMapping("/queryMapMoreThanOnce")
|
||||||
String queryMapMoreThanOnce(@RequestParam MultiValueMap<String, String> queryMap1,
|
String queryMapMoreThanOnce(@RequestParam MultiValueMap<String, String> queryMap1,
|
||||||
@RequestParam MultiValueMap<String, String> queryMap2);
|
@RequestParam MultiValueMap<String, String> queryMap2);
|
||||||
|
|
||||||
@RequestMapping(path = "/queryMapObject")
|
@GetMapping("/queryMapObject")
|
||||||
String queryMapObject(@SpringQueryMap TestObject queryMap, @RequestParam(name = "aParam") String aParam);
|
String queryMapObject(@SpringQueryMap TestObject queryMap, @RequestParam(name = "aParam") String aParam);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface TestTemplate_RequestPart {
|
public interface TestTemplate_RequestPart {
|
||||||
|
|
||||||
@RequestMapping(path = "/requestPart", method = RequestMethod.POST,
|
@PostMapping(path = "/requestPart", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||||
consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
|
||||||
void requestWithMultipleParts(@RequestPart("file") MultipartFile file, @RequestPart("id") String identifier);
|
void requestWithMultipleParts(@RequestPart("file") MultipartFile file, @RequestPart("id") String identifier);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface TestTemplate_MatrixVariable {
|
public interface TestTemplate_MatrixVariable {
|
||||||
|
|
||||||
@RequestMapping(path = "/matrixVariable/{params}")
|
@GetMapping("/matrixVariable/{params}")
|
||||||
String matrixVariable(@MatrixVariable("params") Map<String, Object> params);
|
String matrixVariable(@MatrixVariable("params") Map<String, Object> params);
|
||||||
|
|
||||||
@RequestMapping(path = "/matrixVariableObject/{param}")
|
@GetMapping("/matrixVariableObject/{param}")
|
||||||
String matrixVariableObject(@MatrixVariable("param") Object object);
|
String matrixVariableObject(@MatrixVariable("param") Object object);
|
||||||
|
|
||||||
@RequestMapping(path = "/matrixVariable/{params}")
|
@GetMapping("/matrixVariable/{params}")
|
||||||
String matrixVariableNotNamed(@MatrixVariable Map<String, Object> params);
|
String matrixVariableNotNamed(@MatrixVariable Map<String, Object> params);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@JsonAutoDetect
|
@JsonAutoDetect
|
||||||
@RequestMapping("/advanced")
|
|
||||||
public interface TestTemplate_Advanced {
|
public interface TestTemplate_Advanced {
|
||||||
|
|
||||||
@CollectionFormat(SSV)
|
@CollectionFormat(SSV)
|
||||||
@@ -709,21 +683,20 @@ public class SpringMvcContractTests {
|
|||||||
ResponseEntity<TestObject> getWithCollectionFormat();
|
ResponseEntity<TestObject> getWithCollectionFormat();
|
||||||
|
|
||||||
@ExceptionHandler
|
@ExceptionHandler
|
||||||
@RequestMapping(path = "/test/{id}", method = RequestMethod.PUT, produces = MediaType.APPLICATION_JSON_VALUE)
|
@PutMapping(path = "/test/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
ResponseEntity<TestObject> getTest(@RequestHeader("Authorization") String auth, @PathVariable("id") String id,
|
ResponseEntity<TestObject> getTest(@RequestHeader("Authorization") String auth, @PathVariable("id") String id,
|
||||||
@RequestParam("amount") Integer amount);
|
@RequestParam("amount") Integer amount);
|
||||||
|
|
||||||
@RequestMapping(path = "/test2", method = RequestMethod.PUT, produces = MediaType.APPLICATION_JSON_VALUE)
|
@PutMapping(path = "/test2", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
ResponseEntity<TestObject> getTest2(@RequestHeader(name = "Authorization") String auth,
|
ResponseEntity<TestObject> getTest2(@RequestHeader(name = "Authorization") String auth,
|
||||||
@RequestParam(name = "amount") Integer amount);
|
@RequestParam(name = "amount") Integer amount);
|
||||||
|
|
||||||
@ExceptionHandler
|
@ExceptionHandler
|
||||||
@RequestMapping(path = "/testfallback/{id}", method = RequestMethod.PUT,
|
@PutMapping(path = "/testfallback/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
produces = MediaType.APPLICATION_JSON_VALUE)
|
|
||||||
ResponseEntity<TestObject> getTestFallback(@RequestHeader String Authorization, @PathVariable String id,
|
ResponseEntity<TestObject> getTestFallback(@RequestHeader String Authorization, @PathVariable String id,
|
||||||
@RequestParam Integer amount);
|
@RequestParam Integer amount);
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
|
@GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
TestObject getTest();
|
TestObject getTest();
|
||||||
|
|
||||||
@GetMapping(produces = "application/json")
|
@GetMapping(produces = "application/json")
|
||||||
@@ -735,7 +708,7 @@ public class SpringMvcContractTests {
|
|||||||
|
|
||||||
String CUSTOM_PATTERN = "dd-MM-yyyy HH:mm";
|
String CUSTOM_PATTERN = "dd-MM-yyyy HH:mm";
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET)
|
@GetMapping
|
||||||
String getTest(@RequestParam(name = "localDateTime") @DateTimeFormat(
|
String getTest(@RequestParam(name = "localDateTime") @DateTimeFormat(
|
||||||
pattern = CUSTOM_PATTERN) LocalDateTime localDateTime);
|
pattern = CUSTOM_PATTERN) LocalDateTime localDateTime);
|
||||||
|
|
||||||
@@ -745,7 +718,7 @@ public class SpringMvcContractTests {
|
|||||||
|
|
||||||
String CUSTOM_PATTERN = "$###,###.###";
|
String CUSTOM_PATTERN = "$###,###.###";
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET)
|
@GetMapping
|
||||||
String getTest(@RequestParam("amount") @NumberFormat(pattern = CUSTOM_PATTERN) BigDecimal amount);
|
String getTest(@RequestParam("amount") @NumberFormat(pattern = CUSTOM_PATTERN) BigDecimal amount);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-3
@@ -17,8 +17,7 @@
|
|||||||
package org.springframework.cloud.openfeign.testclients;
|
package org.springframework.cloud.openfeign.testclients;
|
||||||
|
|
||||||
import org.springframework.cloud.openfeign.FeignClient;
|
import org.springframework.cloud.openfeign.FeignClient;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Ryan Baxter
|
* @author Ryan Baxter
|
||||||
@@ -26,7 +25,7 @@ import org.springframework.web.bind.annotation.RequestMethod;
|
|||||||
@FeignClient(name = "localapp")
|
@FeignClient(name = "localapp")
|
||||||
public interface TestClient {
|
public interface TestClient {
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/hello")
|
@GetMapping("/hello")
|
||||||
String getHello();
|
String getHello();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-4
@@ -37,8 +37,7 @@ import org.springframework.context.annotation.Configuration;
|
|||||||
import org.springframework.context.annotation.Primary;
|
import org.springframework.context.annotation.Primary;
|
||||||
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.RequestMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
@@ -83,7 +82,7 @@ public class FeignClientNotPrimaryTests {
|
|||||||
@FeignClient(name = "localapp", primary = false)
|
@FeignClient(name = "localapp", primary = false)
|
||||||
protected interface TestClient {
|
protected interface TestClient {
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, path = "/hello")
|
@GetMapping("/hello")
|
||||||
Hello getHello();
|
Hello getHello();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -101,7 +100,7 @@ public class FeignClientNotPrimaryTests {
|
|||||||
return new PrimaryTestClient();
|
return new PrimaryTestClient();
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, path = "/hello")
|
@GetMapping("/hello")
|
||||||
public Hello getHello() {
|
public Hello getHello() {
|
||||||
return new Hello(HELLO_WORLD_1);
|
return new Hello(HELLO_WORLD_1);
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-5
@@ -27,8 +27,7 @@ import org.springframework.cloud.openfeign.loadbalancer.FeignLoadBalancerAutoCon
|
|||||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
@@ -70,7 +69,7 @@ public class FeignClientValidationTests {
|
|||||||
@FeignClient(name = "example", url = "https://example.com")
|
@FeignClient(name = "example", url = "https://example.com")
|
||||||
interface Client {
|
interface Client {
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/")
|
@GetMapping("/")
|
||||||
@Deprecated
|
@Deprecated
|
||||||
String get();
|
String get();
|
||||||
|
|
||||||
@@ -86,7 +85,7 @@ public class FeignClientValidationTests {
|
|||||||
@FeignClient(name = "example", url = "${feignClient.url:https://example.com}")
|
@FeignClient(name = "example", url = "${feignClient.url:https://example.com}")
|
||||||
interface Client {
|
interface Client {
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/")
|
@GetMapping("/")
|
||||||
@Deprecated
|
@Deprecated
|
||||||
String get();
|
String get();
|
||||||
|
|
||||||
@@ -102,7 +101,7 @@ public class FeignClientValidationTests {
|
|||||||
@FeignClient("foo")
|
@FeignClient("foo")
|
||||||
interface Client {
|
interface Client {
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/")
|
@GetMapping("/")
|
||||||
@Deprecated
|
@Deprecated
|
||||||
String get();
|
String get();
|
||||||
|
|
||||||
|
|||||||
+7
-7
@@ -41,11 +41,11 @@ import org.springframework.context.annotation.Import;
|
|||||||
import org.springframework.http.MediaType;
|
import org.springframework.http.MediaType;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.test.annotation.DirtiesContext;
|
import org.springframework.test.annotation.DirtiesContext;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PatchMapping;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
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.RequestMethod;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
@@ -107,17 +107,17 @@ class FeignHttpClientTests {
|
|||||||
|
|
||||||
protected interface BaseTestClient {
|
protected interface BaseTestClient {
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/hello", produces = MediaType.APPLICATION_JSON_VALUE)
|
@GetMapping(value = "/hello", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
Hello getHello();
|
Hello getHello();
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.PATCH, value = "/hellop", consumes = "application/json")
|
@PatchMapping(value = "/hellop", consumes = "application/json")
|
||||||
ResponseEntity<Void> patchHello(Hello hello);
|
ResponseEntity<Void> patchHello(Hello hello);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected interface UserService {
|
protected interface UserService {
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/users/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
|
@GetMapping(value = "/users/{id}", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||||
User getUser(@PathVariable("id") long id);
|
User getUser(@PathVariable("id") long id);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -136,12 +136,12 @@ class FeignHttpClientTests {
|
|||||||
@Import(NoSecurityConfiguration.class)
|
@Import(NoSecurityConfiguration.class)
|
||||||
protected static class Application implements UserService {
|
protected static class Application implements UserService {
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/hello")
|
@GetMapping("/hello")
|
||||||
public Hello getHello() {
|
public Hello getHello() {
|
||||||
return new Hello("hello world 1");
|
return new Hello("hello world 1");
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.PATCH, value = "/hellop")
|
@PatchMapping("/hellop")
|
||||||
public ResponseEntity<Void> patchHello(@RequestBody Hello hello,
|
public ResponseEntity<Void> patchHello(@RequestBody Hello hello,
|
||||||
@RequestHeader("Content-Length") int contentLength) {
|
@RequestHeader("Content-Length") int contentLength) {
|
||||||
if (contentLength <= 0) {
|
if (contentLength <= 0) {
|
||||||
|
|||||||
+7
-7
@@ -40,11 +40,11 @@ import org.springframework.context.annotation.Configuration;
|
|||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.test.annotation.DirtiesContext;
|
import org.springframework.test.annotation.DirtiesContext;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PatchMapping;
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
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.RequestMethod;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
@@ -107,17 +107,17 @@ class FeignOkHttpTests {
|
|||||||
|
|
||||||
protected interface BaseTestClient {
|
protected interface BaseTestClient {
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/hello")
|
@GetMapping("/hello")
|
||||||
Hello getHello();
|
Hello getHello();
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.PATCH, value = "/hellop", consumes = "application/json")
|
@PatchMapping(value = "/hellop", consumes = "application/json")
|
||||||
ResponseEntity<Void> patchHello(Hello hello);
|
ResponseEntity<Void> patchHello(Hello hello);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected interface UserService {
|
protected interface UserService {
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/users/{id}")
|
@GetMapping("/users/{id}")
|
||||||
User getUser(@PathVariable("id") long id);
|
User getUser(@PathVariable("id") long id);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -138,12 +138,12 @@ class FeignOkHttpTests {
|
|||||||
@Import(NoSecurityConfiguration.class)
|
@Import(NoSecurityConfiguration.class)
|
||||||
protected static class Application implements UserService {
|
protected static class Application implements UserService {
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/hello")
|
@GetMapping("/hello")
|
||||||
public Hello getHello() {
|
public Hello getHello() {
|
||||||
return new Hello("hello world 1");
|
return new Hello("hello world 1");
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.PATCH, value = "/hellop")
|
@PatchMapping("/hellop")
|
||||||
public ResponseEntity<Void> patchHello(@RequestBody Hello hello,
|
public ResponseEntity<Void> patchHello(@RequestBody Hello hello,
|
||||||
@RequestHeader("Content-Length") int contentLength) {
|
@RequestHeader("Content-Length") int contentLength) {
|
||||||
if (contentLength <= 0) {
|
if (contentLength <= 0) {
|
||||||
|
|||||||
+71
-86
@@ -38,7 +38,6 @@ import javax.servlet.http.Part;
|
|||||||
import feign.Client;
|
import feign.Client;
|
||||||
import feign.Logger;
|
import feign.Logger;
|
||||||
import feign.RequestInterceptor;
|
import feign.RequestInterceptor;
|
||||||
import feign.RequestTemplate;
|
|
||||||
import feign.codec.EncodeException;
|
import feign.codec.EncodeException;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
@@ -65,7 +64,6 @@ import org.springframework.context.annotation.Bean;
|
|||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.format.Formatter;
|
import org.springframework.format.Formatter;
|
||||||
import org.springframework.format.FormatterRegistry;
|
|
||||||
import org.springframework.format.annotation.DateTimeFormat;
|
import org.springframework.format.annotation.DateTimeFormat;
|
||||||
import org.springframework.http.HttpEntity;
|
import org.springframework.http.HttpEntity;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
@@ -73,6 +71,8 @@ import org.springframework.http.MediaType;
|
|||||||
import org.springframework.http.ResponseEntity;
|
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.web.bind.annotation.GetMapping;
|
||||||
|
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;
|
||||||
@@ -84,6 +84,9 @@ 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.assertj.core.api.Assertions.assertThatExceptionOfType;
|
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||||
|
import static org.springframework.http.MediaType.APPLICATION_FORM_URLENCODED_VALUE;
|
||||||
|
import static org.springframework.http.MediaType.MULTIPART_FORM_DATA_VALUE;
|
||||||
|
import static org.springframework.http.MediaType.TEXT_PLAIN_VALUE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Spencer Gibb
|
* @author Spencer Gibb
|
||||||
@@ -277,6 +280,13 @@ class ValidFeignClientTests {
|
|||||||
assertThat(testClient.getToString(args)).isEqualTo(expectedResult);
|
assertThat(testClient.getToString(args)).isEqualTo(expectedResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testFormURLEncoded() {
|
||||||
|
Hello hello = new Hello(HELLO_WORLD_1);
|
||||||
|
Hello response = testClient.postFormUrlEncoded(hello);
|
||||||
|
assertThat(response).isEqualTo(hello);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void namedFeignClientWorks() {
|
void namedFeignClientWorks() {
|
||||||
assertThat(namedFeignClient).as("namedFeignClient was null").isNotNull();
|
assertThat(namedFeignClient).as("namedFeignClient was null").isNotNull();
|
||||||
@@ -382,52 +392,42 @@ class ValidFeignClientTests {
|
|||||||
@FeignClient(name = "localapp8")
|
@FeignClient(name = "localapp8")
|
||||||
protected interface MultipartClient {
|
protected interface MultipartClient {
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.POST, path = "/singlePart",
|
@PostMapping(path = "/singlePart", consumes = MULTIPART_FORM_DATA_VALUE, produces = TEXT_PLAIN_VALUE)
|
||||||
consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.TEXT_PLAIN_VALUE)
|
|
||||||
String singlePart(@RequestPart("hello") String hello);
|
String singlePart(@RequestPart("hello") String hello);
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.POST, path = "/singlePojoPart",
|
@PostMapping(path = "/singlePojoPart", consumes = MULTIPART_FORM_DATA_VALUE, produces = TEXT_PLAIN_VALUE)
|
||||||
consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.TEXT_PLAIN_VALUE)
|
|
||||||
String singlePojoPart(@RequestPart("hello") Hello hello);
|
String singlePojoPart(@RequestPart("hello") Hello hello);
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.POST, path = "/multipart",
|
@PostMapping(path = "/multipart", consumes = MULTIPART_FORM_DATA_VALUE, produces = TEXT_PLAIN_VALUE)
|
||||||
consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.TEXT_PLAIN_VALUE)
|
|
||||||
String multipart(@RequestPart("hello") String hello, @RequestPart("world") String world,
|
String multipart(@RequestPart("hello") String hello, @RequestPart("world") String world,
|
||||||
@RequestPart("file") MultipartFile file);
|
@RequestPart("file") MultipartFile file);
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.POST, path = "/multipartPojo",
|
@PostMapping(path = "/multipartPojo", consumes = MULTIPART_FORM_DATA_VALUE, produces = TEXT_PLAIN_VALUE)
|
||||||
consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.TEXT_PLAIN_VALUE)
|
|
||||||
String multipartPojo(@RequestPart("hello") String hello, @RequestPart("world") String world,
|
String multipartPojo(@RequestPart("hello") String hello, @RequestPart("world") String world,
|
||||||
@RequestPart("pojo1") Hello pojo1, @RequestPart("pojo2") Hello pojo2,
|
@RequestPart("pojo1") Hello pojo1, @RequestPart("pojo2") Hello pojo2,
|
||||||
@RequestPart("file") MultipartFile file);
|
@RequestPart("file") MultipartFile file);
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.POST, path = "/multipartNames",
|
@PostMapping(path = "/multipartNames", consumes = MULTIPART_FORM_DATA_VALUE, produces = TEXT_PLAIN_VALUE)
|
||||||
consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.TEXT_PLAIN_VALUE)
|
|
||||||
String requestPartListOfMultipartFilesReturnsPartNames(@RequestPart("files") List<MultipartFile> files);
|
String requestPartListOfMultipartFilesReturnsPartNames(@RequestPart("files") List<MultipartFile> files);
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.POST, path = "/multipartFilenames",
|
@PostMapping(path = "/multipartFilenames", consumes = MULTIPART_FORM_DATA_VALUE, produces = TEXT_PLAIN_VALUE)
|
||||||
consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.TEXT_PLAIN_VALUE)
|
|
||||||
String requestPartListOfMultipartFilesReturnsFileNames(@RequestPart("files") List<MultipartFile> files);
|
String requestPartListOfMultipartFilesReturnsFileNames(@RequestPart("files") List<MultipartFile> files);
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.POST, path = "/multipartPojosFiles",
|
@PostMapping(path = "/multipartPojosFiles", consumes = MULTIPART_FORM_DATA_VALUE, produces = TEXT_PLAIN_VALUE)
|
||||||
consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.TEXT_PLAIN_VALUE)
|
|
||||||
String requestPartListOfPojosAndListOfMultipartFiles(@RequestPart("pojos") List<Hello> pojos,
|
String requestPartListOfPojosAndListOfMultipartFiles(@RequestPart("pojos") List<Hello> pojos,
|
||||||
@RequestPart("files") List<MultipartFile> files);
|
@RequestPart("files") List<MultipartFile> files);
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.POST, path = "/multipartNames",
|
@PostMapping(path = "/multipartNames", consumes = MULTIPART_FORM_DATA_VALUE, produces = TEXT_PLAIN_VALUE)
|
||||||
consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.TEXT_PLAIN_VALUE)
|
|
||||||
String requestBodyListOfMultipartFiles(@RequestBody List<MultipartFile> files);
|
String requestBodyListOfMultipartFiles(@RequestBody List<MultipartFile> files);
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.POST, path = "/multipartNames",
|
@PostMapping(path = "/multipartNames", consumes = MULTIPART_FORM_DATA_VALUE, produces = TEXT_PLAIN_VALUE)
|
||||||
consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.TEXT_PLAIN_VALUE)
|
|
||||||
String requestBodySingleMultipartFile(@RequestBody MultipartFile file);
|
String requestBodySingleMultipartFile(@RequestBody MultipartFile file);
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.POST, path = "/multipartNames",
|
@PostMapping(path = "/multipartNames", consumes = MULTIPART_FORM_DATA_VALUE, produces = TEXT_PLAIN_VALUE)
|
||||||
consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.TEXT_PLAIN_VALUE)
|
|
||||||
String requestBodyMap(@RequestBody Map<String, ?> form);
|
String requestBodyMap(@RequestBody Map<String, ?> form);
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.POST, path = "/invalid",
|
@PostMapping(path = "/invalid", consumes = MediaType.APPLICATION_OCTET_STREAM_VALUE,
|
||||||
consumes = MediaType.APPLICATION_OCTET_STREAM_VALUE, produces = MediaType.TEXT_PLAIN_VALUE)
|
produces = TEXT_PLAIN_VALUE)
|
||||||
String invalid(@RequestBody MultipartFile file);
|
String invalid(@RequestBody MultipartFile file);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -435,36 +435,36 @@ class ValidFeignClientTests {
|
|||||||
@FeignClient(name = "localapp", configuration = TestClientConfig.class)
|
@FeignClient(name = "localapp", configuration = TestClientConfig.class)
|
||||||
protected interface TestClient {
|
protected interface TestClient {
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, path = "/hello")
|
@GetMapping("/hello")
|
||||||
Hello getHello();
|
Hello getHello();
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, path = "/hello")
|
@GetMapping("/hello")
|
||||||
Optional<Hello> getOptionalHello();
|
Optional<Hello> getOptionalHello();
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, path = "${feignClient.methodLevelRequestMappingPath}")
|
@GetMapping("${feignClient.methodLevelRequestMappingPath}")
|
||||||
Hello getHelloUsingPropertyPlaceHolder();
|
Hello getHelloUsingPropertyPlaceHolder();
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, path = "/hellos")
|
@GetMapping("/hellos")
|
||||||
List<Hello> getHellos();
|
List<Hello> getHellos();
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, path = "/hellostrings")
|
@GetMapping("/hellostrings")
|
||||||
List<String> getHelloStrings();
|
List<String> getHelloStrings();
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, path = "/helloheaders")
|
@GetMapping("/helloheaders")
|
||||||
List<String> getHelloHeaders();
|
List<String> getHelloHeaders();
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, path = "/helloheadersplaceholders",
|
@GetMapping(path = "/helloheadersplaceholders",
|
||||||
headers = "myPlaceholderHeader=${feignClient.myPlaceholderHeader}")
|
headers = "myPlaceholderHeader=${feignClient.myPlaceholderHeader}")
|
||||||
String getHelloHeadersPlaceholders();
|
String getHelloHeadersPlaceholders();
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, path = "/helloparams")
|
@GetMapping("/helloparams")
|
||||||
List<String> getParams(@RequestParam("params") List<String> params);
|
List<String> getParams(@RequestParam("params") List<String> params);
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, path = "/formattedparams")
|
@GetMapping("/formattedparams")
|
||||||
List<LocalDate> getFormattedParams(
|
List<LocalDate> getFormattedParams(
|
||||||
@RequestParam("params") @DateTimeFormat(pattern = "dd-MM-yyyy") List<LocalDate> params);
|
@RequestParam("params") @DateTimeFormat(pattern = "dd-MM-yyyy") List<LocalDate> params);
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, path = "/noContent")
|
@GetMapping("/noContent")
|
||||||
ResponseEntity<Void> noContent();
|
ResponseEntity<Void> noContent();
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.HEAD, path = "/head")
|
@RequestMapping(method = RequestMethod.HEAD, path = "/head")
|
||||||
@@ -477,21 +477,24 @@ class ValidFeignClientTests {
|
|||||||
produces = "application/vnd.io.spring.cloud.test.v1+json", path = "/complex")
|
produces = "application/vnd.io.spring.cloud.test.v1+json", path = "/complex")
|
||||||
String moreComplexContentType(String body);
|
String moreComplexContentType(String body);
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, path = "/tostring")
|
@GetMapping("/tostring")
|
||||||
String getToString(@RequestParam("arg") Arg arg);
|
String getToString(@RequestParam("arg") Arg arg);
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, path = "/tostring2")
|
@GetMapping("/tostring2")
|
||||||
String getToString(@RequestParam("arg") OtherArg arg);
|
String getToString(@RequestParam("arg") OtherArg arg);
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, path = "/tostringcollection")
|
@GetMapping("/tostringcollection")
|
||||||
Collection<String> getToString(@RequestParam("arg") Collection<OtherArg> args);
|
Collection<String> getToString(@RequestParam("arg") Collection<OtherArg> args);
|
||||||
|
|
||||||
|
@PostMapping(path = "/form-urlencoded", consumes = APPLICATION_FORM_URLENCODED_VALUE)
|
||||||
|
Hello postFormUrlEncoded(Hello hello);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@FeignClient(name = "localapp1")
|
@FeignClient(name = "localapp1")
|
||||||
protected interface TestClientServiceId {
|
protected interface TestClientServiceId {
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, path = "/hello")
|
@GetMapping("/hello")
|
||||||
Hello getHello();
|
Hello getHello();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -499,10 +502,10 @@ class ValidFeignClientTests {
|
|||||||
@FeignClient(name = "localapp2", decode404 = true)
|
@FeignClient(name = "localapp2", decode404 = true)
|
||||||
protected interface DecodingTestClient {
|
protected interface DecodingTestClient {
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, path = "/notFound")
|
@GetMapping("/notFound")
|
||||||
ResponseEntity<String> notFound();
|
ResponseEntity<String> notFound();
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, path = "/notFound")
|
@GetMapping("/notFound")
|
||||||
Optional<String> optional();
|
Optional<String> optional();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -526,22 +529,12 @@ class ValidFeignClientTests {
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public RequestInterceptor interceptor1() {
|
public RequestInterceptor interceptor1() {
|
||||||
return new RequestInterceptor() {
|
return template -> template.header(MYHEADER1, "myheader1value");
|
||||||
@Override
|
|
||||||
public void apply(RequestTemplate template) {
|
|
||||||
template.header(MYHEADER1, "myheader1value");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public RequestInterceptor interceptor2() {
|
public RequestInterceptor interceptor2() {
|
||||||
return new RequestInterceptor() {
|
return template -> template.header(MYHEADER2, "myheader2value");
|
||||||
@Override
|
|
||||||
public void apply(RequestTemplate template) {
|
|
||||||
template.header(MYHEADER2, "myheader2value");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -570,11 +563,7 @@ class ValidFeignClientTests {
|
|||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
FeignFormatterRegistrar feignFormatterRegistrar() {
|
FeignFormatterRegistrar feignFormatterRegistrar() {
|
||||||
return new FeignFormatterRegistrar() {
|
return registry -> registry.addFormatter(new Formatter<OtherArg>() {
|
||||||
|
|
||||||
@Override
|
|
||||||
public void registerFormatters(FormatterRegistry registry) {
|
|
||||||
registry.addFormatter(new Formatter<OtherArg>() {
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String print(OtherArg object, Locale locale) {
|
public String print(OtherArg object, Locale locale) {
|
||||||
@@ -590,31 +579,29 @@ class ValidFeignClientTests {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public AbstractFormWriter jsonFormWriter() {
|
public AbstractFormWriter jsonFormWriter() {
|
||||||
return new JsonFormWriter();
|
return new JsonFormWriter();
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, path = "/hello")
|
@GetMapping("/hello")
|
||||||
public Hello getHello() {
|
public Hello getHello() {
|
||||||
return new Hello(HELLO_WORLD_1);
|
return new Hello(HELLO_WORLD_1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, path = "/hello2")
|
@GetMapping("/hello2")
|
||||||
public Hello getHello2() {
|
public Hello getHello2() {
|
||||||
return new Hello(OI_TERRA_2);
|
return new Hello(OI_TERRA_2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, path = "/hellos")
|
@GetMapping("/hellos")
|
||||||
public List<Hello> getHellos() {
|
public List<Hello> getHellos() {
|
||||||
ArrayList<Hello> hellos = getHelloList();
|
ArrayList<Hello> hellos = getHelloList();
|
||||||
return hellos;
|
return hellos;
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, path = "/hellostrings")
|
@GetMapping("/hellostrings")
|
||||||
public List<String> getHelloStrings() {
|
public List<String> getHelloStrings() {
|
||||||
ArrayList<String> hellos = new ArrayList<>();
|
ArrayList<String> hellos = new ArrayList<>();
|
||||||
hellos.add(HELLO_WORLD_1);
|
hellos.add(HELLO_WORLD_1);
|
||||||
@@ -622,7 +609,7 @@ class ValidFeignClientTests {
|
|||||||
return hellos;
|
return hellos;
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, path = "/helloheaders")
|
@GetMapping("/helloheaders")
|
||||||
public List<String> getHelloHeaders(@RequestHeader(MYHEADER1) String myheader1,
|
public List<String> getHelloHeaders(@RequestHeader(MYHEADER1) String myheader1,
|
||||||
@RequestHeader(MYHEADER2) String myheader2) {
|
@RequestHeader(MYHEADER2) String myheader2) {
|
||||||
ArrayList<String> headers = new ArrayList<>();
|
ArrayList<String> headers = new ArrayList<>();
|
||||||
@@ -631,23 +618,23 @@ class ValidFeignClientTests {
|
|||||||
return headers;
|
return headers;
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, path = "/helloheadersplaceholders")
|
@GetMapping("/helloheadersplaceholders")
|
||||||
public String getHelloHeadersPlaceholders(@RequestHeader("myPlaceholderHeader") String myPlaceholderHeader) {
|
public String getHelloHeadersPlaceholders(@RequestHeader("myPlaceholderHeader") String myPlaceholderHeader) {
|
||||||
return myPlaceholderHeader;
|
return myPlaceholderHeader;
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, path = "/helloparams")
|
@GetMapping("/helloparams")
|
||||||
public List<String> getParams(@RequestParam("params") List<String> params) {
|
public List<String> getParams(@RequestParam("params") List<String> params) {
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, path = "/formattedparams")
|
@GetMapping("/formattedparams")
|
||||||
public List<LocalDate> getFormattedParams(
|
public List<LocalDate> getFormattedParams(
|
||||||
@RequestParam("params") @DateTimeFormat(pattern = "dd-MM-yyyy") List<LocalDate> params) {
|
@RequestParam("params") @DateTimeFormat(pattern = "dd-MM-yyyy") List<LocalDate> params) {
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, path = "/noContent")
|
@GetMapping("/noContent")
|
||||||
ResponseEntity<Void> noContent() {
|
ResponseEntity<Void> noContent() {
|
||||||
return ResponseEntity.noContent().build();
|
return ResponseEntity.noContent().build();
|
||||||
}
|
}
|
||||||
@@ -662,7 +649,7 @@ class ValidFeignClientTests {
|
|||||||
throw new RuntimeException("always fails");
|
throw new RuntimeException("always fails");
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, path = "/notFound")
|
@GetMapping("/notFound")
|
||||||
ResponseEntity<String> notFound() {
|
ResponseEntity<String> notFound() {
|
||||||
return ResponseEntity.status(HttpStatus.NOT_FOUND).body((String) null);
|
return ResponseEntity.status(HttpStatus.NOT_FOUND).body((String) null);
|
||||||
}
|
}
|
||||||
@@ -676,17 +663,17 @@ class ValidFeignClientTests {
|
|||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, path = "/tostring")
|
@GetMapping("/tostring")
|
||||||
String getToString(@RequestParam("arg") Arg arg) {
|
String getToString(@RequestParam("arg") Arg arg) {
|
||||||
return arg.toString();
|
return arg.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, path = "/tostring2")
|
@GetMapping("/tostring2")
|
||||||
String getToString(@RequestParam("arg") OtherArg arg) {
|
String getToString(@RequestParam("arg") OtherArg arg) {
|
||||||
return arg.value;
|
return arg.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, path = "/tostringcollection")
|
@GetMapping("/tostringcollection")
|
||||||
Collection<String> getToString(@RequestParam("arg") Collection<OtherArg> args) {
|
Collection<String> getToString(@RequestParam("arg") Collection<OtherArg> args) {
|
||||||
List<String> result = new ArrayList<>();
|
List<String> result = new ArrayList<>();
|
||||||
for (OtherArg arg : args) {
|
for (OtherArg arg : args) {
|
||||||
@@ -695,47 +682,40 @@ class ValidFeignClientTests {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.POST, path = "/singlePart",
|
@PostMapping(path = "/singlePart", consumes = MULTIPART_FORM_DATA_VALUE, produces = TEXT_PLAIN_VALUE)
|
||||||
consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.TEXT_PLAIN_VALUE)
|
|
||||||
String singlePart(@RequestPart("hello") String hello) {
|
String singlePart(@RequestPart("hello") String hello) {
|
||||||
return hello;
|
return hello;
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.POST, path = "/singlePojoPart",
|
@PostMapping(path = "/singlePojoPart", consumes = MULTIPART_FORM_DATA_VALUE, produces = TEXT_PLAIN_VALUE)
|
||||||
consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.TEXT_PLAIN_VALUE)
|
|
||||||
String singlePojoPart(@RequestPart("hello") Hello hello) {
|
String singlePojoPart(@RequestPart("hello") Hello hello) {
|
||||||
return hello.getMessage();
|
return hello.getMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.POST, path = "/multipart",
|
@PostMapping(path = "/multipart", consumes = MULTIPART_FORM_DATA_VALUE, produces = TEXT_PLAIN_VALUE)
|
||||||
consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.TEXT_PLAIN_VALUE)
|
|
||||||
String multipart(@RequestPart("hello") String hello, @RequestPart("world") String world,
|
String multipart(@RequestPart("hello") String hello, @RequestPart("world") String world,
|
||||||
@RequestPart("file") MultipartFile file) {
|
@RequestPart("file") MultipartFile file) {
|
||||||
return hello + world + file.getOriginalFilename();
|
return hello + world + file.getOriginalFilename();
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.POST, path = "/multipartPojo",
|
@PostMapping(path = "/multipartPojo", consumes = MULTIPART_FORM_DATA_VALUE, produces = TEXT_PLAIN_VALUE)
|
||||||
consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.TEXT_PLAIN_VALUE)
|
|
||||||
String multipartPojo(@RequestPart("hello") String hello, @RequestPart("world") String world,
|
String multipartPojo(@RequestPart("hello") String hello, @RequestPart("world") String world,
|
||||||
@RequestPart("pojo1") Hello pojo1, @RequestPart("pojo2") Hello pojo2,
|
@RequestPart("pojo1") Hello pojo1, @RequestPart("pojo2") Hello pojo2,
|
||||||
@RequestPart("file") MultipartFile file) {
|
@RequestPart("file") MultipartFile file) {
|
||||||
return hello + world + pojo1.getMessage() + pojo2.getMessage() + file.getOriginalFilename();
|
return hello + world + pojo1.getMessage() + pojo2.getMessage() + file.getOriginalFilename();
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.POST, path = "/multipartNames",
|
@PostMapping(path = "/multipartNames", consumes = MULTIPART_FORM_DATA_VALUE, produces = TEXT_PLAIN_VALUE)
|
||||||
consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.TEXT_PLAIN_VALUE)
|
|
||||||
String multipartNames(HttpServletRequest request) throws Exception {
|
String multipartNames(HttpServletRequest request) throws Exception {
|
||||||
return request.getParts().stream().map(Part::getName).collect(Collectors.joining(","));
|
return request.getParts().stream().map(Part::getName).collect(Collectors.joining(","));
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.POST, path = "/multipartFilenames",
|
@PostMapping(path = "/multipartFilenames", consumes = MULTIPART_FORM_DATA_VALUE, produces = TEXT_PLAIN_VALUE)
|
||||||
consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.TEXT_PLAIN_VALUE)
|
|
||||||
String multipartFilenames(HttpServletRequest request) throws Exception {
|
String multipartFilenames(HttpServletRequest request) throws Exception {
|
||||||
return request.getParts().stream().map(Part::getSubmittedFileName).collect(Collectors.joining(","));
|
return request.getParts().stream().map(Part::getSubmittedFileName).collect(Collectors.joining(","));
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.POST, path = "/multipartPojosFiles",
|
@PostMapping(path = "/multipartPojosFiles", consumes = MULTIPART_FORM_DATA_VALUE, produces = TEXT_PLAIN_VALUE)
|
||||||
consumes = MediaType.MULTIPART_FORM_DATA_VALUE, produces = MediaType.TEXT_PLAIN_VALUE)
|
|
||||||
String requestPartListOfPojosAndListOfMultipartFiles(@RequestPart("pojos") List<Hello> pojos,
|
String requestPartListOfPojosAndListOfMultipartFiles(@RequestPart("pojos") List<Hello> pojos,
|
||||||
@RequestPart("files") List<MultipartFile> files) {
|
@RequestPart("files") List<MultipartFile> files) {
|
||||||
StringBuilder result = new StringBuilder();
|
StringBuilder result = new StringBuilder();
|
||||||
@@ -751,6 +731,11 @@ class ValidFeignClientTests {
|
|||||||
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 {
|
||||||
|
|||||||
+2
-3
@@ -35,8 +35,7 @@ import org.springframework.context.annotation.Configuration;
|
|||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
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.RequestMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
@@ -70,7 +69,7 @@ public class FeignClientEnvVarTests {
|
|||||||
@Import(NoSecurityConfiguration.class)
|
@Import(NoSecurityConfiguration.class)
|
||||||
protected static class Application {
|
protected static class Application {
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/hello")
|
@GetMapping("/hello")
|
||||||
public String getHello() {
|
public String getHello() {
|
||||||
return "hello world 1";
|
return "hello world 1";
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-5
@@ -37,8 +37,7 @@ import org.springframework.context.annotation.Configuration;
|
|||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
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.RequestMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMethod;
|
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
@@ -83,7 +82,7 @@ public class FeignClientScanningTests {
|
|||||||
@FeignClient("localapp123")
|
@FeignClient("localapp123")
|
||||||
protected interface TestClient {
|
protected interface TestClient {
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/hello")
|
@GetMapping("/hello")
|
||||||
String getHello();
|
String getHello();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -91,7 +90,7 @@ public class FeignClientScanningTests {
|
|||||||
@FeignClient("${feignClient.localappName}")
|
@FeignClient("${feignClient.localappName}")
|
||||||
protected interface TestClientByKey {
|
protected interface TestClientByKey {
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/hello")
|
@GetMapping("/hello")
|
||||||
String getHello();
|
String getHello();
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -104,7 +103,7 @@ public class FeignClientScanningTests {
|
|||||||
@Import(NoSecurityConfiguration.class)
|
@Import(NoSecurityConfiguration.class)
|
||||||
protected static class Application {
|
protected static class Application {
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.GET, value = "/hello")
|
@GetMapping("/hello")
|
||||||
public String getHello() {
|
public String getHello() {
|
||||||
return "hello world 1";
|
return "hello world 1";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>3.0.3</version>
|
<version>3.0.6-SNAPSHOT</version>
|
||||||
<relativePath/>
|
<relativePath/>
|
||||||
</parent>
|
</parent>
|
||||||
<artifactId>spring-cloud-openfeign-dependencies</artifactId>
|
<artifactId>spring-cloud-openfeign-dependencies</artifactId>
|
||||||
<version>3.0.3</version>
|
<version>3.0.7-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>3.0.3</version>
|
<version>3.0.7-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