Compare commits

..
18 Commits
Author SHA1 Message Date
buildmaster 53428758ad Update SNAPSHOT to 4.0.0-M1 2022-01-27 21:45:39 +00:00
buildmaster 59ac5c1b3c Bumping versions 2022-01-27 00:24:12 +00:00
spencergibb 4f7892f34d formatting 2022-01-26 16:33:21 -05:00
buildmaster 261fc58a5e Bumping versions 2022-01-20 00:23:54 +00:00
Olga MaciaszekSharma 67e8c9072d Merge remote-tracking branch 'origin/3.1.x' 2022-01-17 12:41:39 +01:00
Olga MaciaszekSharma 7b08279aae Merge remote-tracking branch 'origin/3.1.x' 2022-01-17 10:51:54 +01:00
buildmaster f60859120d Bumping versions 2022-01-15 00:23:41 +00:00
Olga MaciaszekSharma c665d2c029 Merge remote-tracking branch 'origin/3.1.x' 2022-01-14 20:02:56 +01:00
Olga MaciaszekSharma 7f425704e4 Merge remote-tracking branch 'origin/3.1.x' 2022-01-14 17:23:03 +01:00
Olga MaciaszekSharma 6c130af613 Merge remote-tracking branch 'origin/3.1.x' 2022-01-14 17:04:11 +01:00
Olga MaciaszekSharma 98b2511d1f Merge remote-tracking branch 'origin/3.1.x' 2022-01-12 18:14:46 +01:00
Olga MaciaszekSharma 10ad8a0c6e Update license entries. 2022-01-11 15:05:02 +01:00
Olga MaciaszekSharma 505894315d Merge remote-tracking branch 'origin/3.1.x' 2022-01-11 15:03:45 +01:00
Olga MaciaszekSharma e2048b3719 Merge remote-tracking branch 'origin/3.1.x' 2022-01-11 14:28:05 +01:00
buildmaster e389726ba2 Bumping versions 2022-01-06 00:32:53 +00:00
Spencer Gibb 2cf8adf482 Update github actions to use java 17 2022-01-04 13:16:49 -05:00
spencergibb 6a1d9fe074 Updates to version 4.0.0-SNAPSHOT
Updates to java 17, framework 6, boot 3 and javax -> jakarta
2022-01-04 13:02:13 -05:00
spencergibb b6b16a034a Updates to version 4.0.0-SNAPSHOT
Updates to java 17, framework 6, boot 3 and javax -> jakarta
2022-01-04 12:26:00 -05:00
36 changed files with 55 additions and 430 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ jobs:
strategy:
matrix:
java: ["8", "11", "16"]
java: ["17"]
steps:
- uses: actions/checkout@v2
+1 -1
View File
@@ -1,3 +1,3 @@
# Enable auto-env through the sdkman_auto_env config
# Add key=value pairs of SDKs to use below
java=8.0.292.hs-adpt
java=17.0.1-tem
+1 -2
View File
@@ -40,8 +40,7 @@ and binding to the Spring Environment and other Spring programming model idioms.
== Building
:jdkversion: 17
:jdkversion: 1.8
=== Basic Compile and Test
+1 -3
View File
@@ -6,7 +6,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-openfeign</artifactId>
<version>3.1.3</version>
<version>4.0.0-M1</version>
</parent>
<artifactId>spring-cloud-openfeign-docs</artifactId>
<packaging>jar</packaging>
@@ -17,8 +17,6 @@
<main.basedir>${basedir}/..</main.basedir>
<configprops.inclusionPattern>feign.*</configprops.inclusionPattern>
<upload-docs-zip.phase>deploy</upload-docs-zip.phase>
<!-- Don't upload docs jar to central / repo.spring.io -->
<maven-deploy-plugin-default.phase>none</maven-deploy-plugin-default.phase>
</properties>
<dependencies>
<dependency>
-1
View File
@@ -2,7 +2,6 @@
|Name | Default | Description
|feign.autoconfiguration.jackson.enabled | `false` | If true, PageJacksonModule and SortJacksonModule bean will be provided for Jackson page decoding.
|feign.circuitbreaker.alphanumeric-ids.enabled | `false` | If true, Circuit Breaker ids will only contain alphanumeric characters to allow for configuration via configuration properties.
|feign.circuitbreaker.enabled | `false` | If true, an OpenFeign client will be wrapped with a Spring Cloud CircuitBreaker circuit breaker.
|feign.circuitbreaker.group.enabled | `false` | If true, an OpenFeign client will be wrapped with a Spring Cloud CircuitBreaker circuit breaker with with group.
|feign.client.config | |
@@ -372,47 +372,6 @@ public class FooConfiguration {
To enable Spring Cloud CircuitBreaker group set the `feign.circuitbreaker.group.enabled` property to `true` (by default `false`).
[[spring-clou-feign-circuitbreaker-configurationproperties]]
=== Configuring CircuitBreakers With Configuration Properties
You can configure CircuitBreakers via configuration properties. To do set
`feign.circuitbreaker.alphanumeric-ids.enabled` to `true`. Since
you cannot use characters like `#`, `(`, `)` `,` in configuration property names we need to
change the naming convention for the ids of the circuit breakers generated by OpenFeign. The above
property will do this for you.
For example, if you had this Feign client
[source,java,indent=0]
----
@FeignClienturl = "http://localhost:8080")
public interface DemoClient {
@GetMapping("demo")
String getDemo();
}
----
You could configure it using configuration properties by doing the following
[source,yaml,indent=0]
----
feign:
circuitbreaker:
enabled: true
alphanumeric-ids:
enabled: true
resilience4j:
circuitbreaker:
instances:
DemoClientgetDemo:
minimumNumberOfCalls: 69
timelimiter:
instances:
DemoClientgetDemo:
timeoutDuration: 10s
----
[[spring-cloud-feign-circuitbreaker-fallback]]
=== Feign Spring Cloud CircuitBreaker Fallbacks
+3 -10
View File
@@ -4,14 +4,14 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>spring-cloud-openfeign</artifactId>
<version>3.1.3</version>
<version>4.0.0-M1</version>
<packaging>pom</packaging>
<name>Spring Cloud OpenFeign</name>
<description>Spring Cloud OpenFeign</description>
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-build</artifactId>
<version>3.1.3</version>
<version>4.0.0-M1</version>
<relativePath/>
</parent>
<scm>
@@ -26,7 +26,7 @@
<properties>
<main.basedir>${basedir}</main.basedir>
<jackson.version>2.11.3</jackson.version>
<spring-cloud-commons.version>3.1.3</spring-cloud-commons.version>
<spring-cloud-commons.version>4.0.0-M1</spring-cloud-commons.version>
<!-- Plugin versions -->
<maven-eclipse-plugin.version>2.10</maven-eclipse-plugin.version>
@@ -64,13 +64,6 @@
</additionalConfig>
</configuration>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
+1 -1
View File
@@ -6,7 +6,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-openfeign</artifactId>
<version>3.1.3</version>
<version>4.0.0-M1</version>
<relativePath>..</relativePath> <!-- lookup parent from repository -->
</parent>
<artifactId>spring-cloud-openfeign-core</artifactId>
@@ -25,8 +25,6 @@ import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;
import javax.annotation.PreDestroy;
import com.fasterxml.jackson.databind.Module;
import feign.Capability;
import feign.Client;
@@ -36,6 +34,7 @@ import feign.Target;
import feign.hc5.ApacheHttp5Client;
import feign.httpclient.ApacheHttpClient;
import feign.okhttp.OkHttpClient;
import jakarta.annotation.PreDestroy;
import okhttp3.ConnectionPool;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
@@ -166,19 +165,10 @@ public class FeignAutoConfiguration {
@Bean
@ConditionalOnMissingBean(CircuitBreakerNameResolver.class)
@ConditionalOnProperty(value = "feign.circuitbreaker.alphanumeric-ids.enabled", havingValue = "false",
matchIfMissing = true)
public CircuitBreakerNameResolver circuitBreakerNameResolver() {
return new DefaultCircuitBreakerNameResolver();
}
@Bean
@ConditionalOnMissingBean(CircuitBreakerNameResolver.class)
@ConditionalOnProperty(value = "feign.circuitbreaker.alphanumeric-ids.enabled", havingValue = "true")
public CircuitBreakerNameResolver alphanumericCircuitBreakerNameResolver() {
return new AlphanumericCircuitBreakerNameResolver();
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnBean(CircuitBreakerFactory.class)
@@ -198,15 +188,6 @@ public class FeignAutoConfiguration {
}
static class AlphanumericCircuitBreakerNameResolver extends DefaultCircuitBreakerNameResolver {
@Override
public String resolveCircuitBreakerName(String feignClientName, Target<?> target, Method method) {
return super.resolveCircuitBreakerName(feignClientName, target, method).replaceAll("[^a-zA-Z0-9]", "");
}
}
}
// the following configuration is for alternate feign clients if
@@ -17,7 +17,6 @@
package org.springframework.cloud.openfeign;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.LinkedHashMap;
@@ -30,7 +29,6 @@ import feign.Target;
import org.springframework.cloud.client.circuitbreaker.CircuitBreaker;
import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory;
import org.springframework.cloud.client.circuitbreaker.NoFallbackAvailableException;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
@@ -97,29 +95,15 @@ class FeignCircuitBreakerInvocationHandler implements InvocationHandler {
try {
return this.fallbackMethodMap.get(method).invoke(fallback, args);
}
catch (Exception exception) {
unwrapAndRethrow(exception);
catch (Exception e) {
throw new IllegalStateException(e);
}
return null;
};
return circuitBreaker.run(supplier, fallbackFunction);
}
return circuitBreaker.run(supplier);
}
private void unwrapAndRethrow(Exception exception) {
if (exception instanceof InvocationTargetException || exception instanceof NoFallbackAvailableException) {
Throwable underlyingException = exception.getCause();
if (underlyingException instanceof RuntimeException) {
throw (RuntimeException) underlyingException;
}
if (underlyingException != null) {
throw new IllegalStateException(underlyingException);
}
throw new IllegalStateException(exception);
}
}
private Supplier<Object> asSupplier(final Method method, final Object[] args) {
final RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
return () -> {
@@ -69,7 +69,6 @@ import org.springframework.util.StringUtils;
* @author Sam Kruglov
* @author Jasbir Singh
* @author Hyeonmin Park
* @author Felix Dittrich
*/
public class FeignClientFactoryBean
implements FactoryBean<Object>, InitializingBean, ApplicationContextAware, BeanFactoryAware {
@@ -133,6 +132,7 @@ public class FeignClientFactoryBean
// @formatter:on
configureFeign(context, builder);
applyBuildCustomizers(context, builder);
return builder;
}
@@ -374,7 +374,6 @@ public class FeignClientFactoryBean
Client client = getOptional(context, Client.class);
if (client != null) {
builder.client(client);
applyBuildCustomizers(context, builder);
Targeter targeter = get(context, Targeter.class);
return targeter.target(this, builder, context, target);
}
@@ -444,9 +443,6 @@ public class FeignClientFactoryBean
}
builder.client(client);
}
applyBuildCustomizers(context, builder);
Targeter targeter = get(context, Targeter.class);
return (T) targeter.target(this, builder, context, new HardCodedTarget<>(type, name, url));
}
@@ -23,11 +23,11 @@ import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;
import javax.annotation.PreDestroy;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import jakarta.annotation.PreDestroy;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hc.client5.http.config.RequestConfig;
@@ -20,8 +20,7 @@ import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;
import javax.annotation.PreDestroy;
import jakarta.annotation.PreDestroy;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.client.config.RequestConfig;
@@ -19,8 +19,7 @@ package org.springframework.cloud.openfeign.clientconfig;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
import javax.annotation.PreDestroy;
import jakarta.annotation.PreDestroy;
import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 the original author or authors.
* Copyright 2016-2022 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.
@@ -110,9 +110,8 @@ public class FeignBlockingLoadBalancerClient implements Client {
}
String reconstructedUrl = loadBalancerClient.reconstructURI(instance, originalUri).toString();
Request newRequest = buildRequest(request, reconstructedUrl);
LoadBalancerProperties loadBalancerProperties = loadBalancerClientFactory.getProperties(serviceId);
return executeWithLoadBalancerLifecycleProcessing(delegate, options, newRequest, lbRequest, lbResponse,
supportedLifecycleProcessors, loadBalancerProperties.isUseRawStatusCodeInResponseData());
supportedLifecycleProcessors);
}
protected Request buildRequest(Request request, String reconstructedUrl) {
@@ -50,15 +50,14 @@ final class LoadBalancerUtils {
static Response executeWithLoadBalancerLifecycleProcessing(Client feignClient, Request.Options options,
Request feignRequest, org.springframework.cloud.client.loadbalancer.Request lbRequest,
org.springframework.cloud.client.loadbalancer.Response<ServiceInstance> lbResponse,
Set<LoadBalancerLifecycle> supportedLifecycleProcessors, boolean loadBalanced, boolean useRawStatusCodes)
throws IOException {
Set<LoadBalancerLifecycle> supportedLifecycleProcessors, boolean loadBalanced) throws IOException {
supportedLifecycleProcessors.forEach(lifecycle -> lifecycle.onStartRequest(lbRequest, lbResponse));
try {
Response response = feignClient.execute(feignRequest, options);
if (loadBalanced) {
supportedLifecycleProcessors.forEach(
lifecycle -> lifecycle.onComplete(new CompletionContext<>(CompletionContext.Status.SUCCESS,
lbRequest, lbResponse, buildResponseData(response, useRawStatusCodes))));
lbRequest, lbResponse, buildResponseData(response))));
}
return response;
}
@@ -71,12 +70,9 @@ final class LoadBalancerUtils {
}
}
static ResponseData buildResponseData(Response response, boolean useRawStatusCodes) {
static ResponseData buildResponseData(Response response) {
HttpHeaders responseHeaders = new HttpHeaders();
response.headers().forEach((key, value) -> responseHeaders.put(key, new ArrayList<>(value)));
if (useRawStatusCodes) {
return new ResponseData(responseHeaders, null, buildRequestData(response.request()), response.status());
}
return new ResponseData(HttpStatus.resolve(response.status()), responseHeaders, null,
buildRequestData(response.request()));
}
@@ -91,9 +87,9 @@ final class LoadBalancerUtils {
static Response executeWithLoadBalancerLifecycleProcessing(Client feignClient, Request.Options options,
Request feignRequest, org.springframework.cloud.client.loadbalancer.Request lbRequest,
org.springframework.cloud.client.loadbalancer.Response<ServiceInstance> lbResponse,
Set<LoadBalancerLifecycle> supportedLifecycleProcessors, boolean useRawStatusCodes) throws IOException {
Set<LoadBalancerLifecycle> supportedLifecycleProcessors) throws IOException {
return executeWithLoadBalancerLifecycleProcessing(feignClient, options, feignRequest, lbRequest, lbResponse,
supportedLifecycleProcessors, true, useRawStatusCodes);
supportedLifecycleProcessors, true);
}
}
@@ -163,10 +163,9 @@ public class RetryableFeignBlockingLoadBalancerClient implements Client {
}
org.springframework.cloud.client.loadbalancer.Response<ServiceInstance> lbResponse = new DefaultResponse(
retrievedServiceInstance);
LoadBalancerProperties loadBalancerProperties = loadBalancerClientFactory.getProperties(serviceId);
Response response = LoadBalancerUtils.executeWithLoadBalancerLifecycleProcessing(delegate, options,
feignRequest, lbRequest, lbResponse, supportedLifecycleProcessors, retrievedServiceInstance != null,
loadBalancerProperties.isUseRawStatusCodeInResponseData());
feignRequest, lbRequest, lbResponse, supportedLifecycleProcessors,
retrievedServiceInstance != null);
int responseStatus = response.status();
if (retryPolicy != null && retryPolicy.retryableStatusCode(responseStatus)) {
if (LOG.isDebugEnabled()) {
@@ -1,5 +1,5 @@
/*
* Copyright 2015-2021 the original author or authors.
* Copyright 2015-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -1,5 +1,5 @@
/*
* Copyright 2016-2021 the original author or authors.
* Copyright 2016-2022 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.
@@ -196,21 +196,6 @@ public class PageJacksonModule extends Module {
return delegate.isEmpty();
}
@Override
public int hashCode() {
return delegate.hashCode();
}
@Override
public boolean equals(Object obj) {
return delegate.equals(obj);
}
@Override
public String toString() {
return delegate.toString();
}
}
}
@@ -14,12 +14,6 @@
"description": "If true, an OpenFeign client will be wrapped with a Spring Cloud CircuitBreaker circuit breaker.",
"defaultValue": "false"
},
{
"name": "feign.circuitbreaker.alphanumeric-ids.enabled",
"type": "java.lang.Boolean",
"description": "If true, Circuit Breaker ids will only contain alphanumeric characters to allow for configuration via configuration properties.",
"defaultValue": "false"
},
{
"name": "feign.circuitbreaker.group.enabled",
"type": "java.lang.Boolean",
@@ -17,56 +17,35 @@
package org.springframework.cloud.openfeign;
import java.lang.reflect.Field;
import java.util.stream.Stream;
import feign.Client;
import feign.Feign;
import feign.Logger;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.mockito.ArgumentCaptor;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Primary;
import org.springframework.core.annotation.Order;
import org.springframework.util.ReflectionUtils;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doCallRealMethod;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
/**
* @author Matt King
* @author Sam Kruglov
* @author Felix Dittrich
* @author Olga Maciaszek-Sharma
*/
class FeignBuilderCustomizerTests {
private static final Targeter targeterSpy = spy(DefaultTargeter.class);
private static final Client defaultClient = mock(Client.class);
@Test
void testBuilderCustomizer() {
ArgumentCaptor<Feign.Builder> feignBuilderCaptor = ArgumentCaptor.forClass(Feign.Builder.class);
doCallRealMethod().when(targeterSpy).target(any(), feignBuilderCaptor.capture(), any(), any());
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
FeignBuilderCustomizerTests.SampleConfiguration2.class);
FeignClientFactoryBean clientFactoryBean = context.getBean(FeignClientFactoryBean.class);
clientFactoryBean.getTarget();
FeignContext feignContext = context.getBean(FeignContext.class);
Assertions.assertNotNull(feignBuilderCaptor.getValue());
Feign.Builder builder = feignBuilderCaptor.getValue();
Feign.Builder builder = clientFactoryBean.feign(feignContext);
assertFeignBuilderField(builder, "logLevel", Logger.Level.HEADERS);
assertFeignBuilderField(builder, "decode404", true);
@@ -83,17 +62,13 @@ class FeignBuilderCustomizerTests {
@Test
void testBuildCustomizerOrdered() {
ArgumentCaptor<Feign.Builder> feignBuilderCaptor = ArgumentCaptor.forClass(Feign.Builder.class);
doCallRealMethod().when(targeterSpy).target(any(), feignBuilderCaptor.capture(), any(), any());
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
FeignBuilderCustomizerTests.SampleConfiguration3.class);
FeignClientFactoryBean clientFactoryBean = context.getBean(FeignClientFactoryBean.class);
clientFactoryBean.getTarget();
FeignContext feignContext = context.getBean(FeignContext.class);
Assertions.assertNotNull(feignBuilderCaptor.getValue());
Feign.Builder builder = feignBuilderCaptor.getValue();
Feign.Builder builder = clientFactoryBean.feign(feignContext);
assertFeignBuilderField(builder, "logLevel", Logger.Level.FULL);
assertFeignBuilderField(builder, "decode404", true);
@@ -102,19 +77,15 @@ class FeignBuilderCustomizerTests {
@Test
void testBuildCustomizerOrderedWithAdditional() {
ArgumentCaptor<Feign.Builder> feignBuilderCaptor = ArgumentCaptor.forClass(Feign.Builder.class);
doCallRealMethod().when(targeterSpy).target(any(), feignBuilderCaptor.capture(), any(), any());
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
FeignBuilderCustomizerTests.SampleConfiguration3.class);
FeignClientFactoryBean clientFactoryBean = context.getBean(FeignClientFactoryBean.class);
clientFactoryBean.addCustomizer(builder -> builder.logLevel(Logger.Level.BASIC));
clientFactoryBean.addCustomizer(Feign.Builder::doNotCloseAfterDecode);
clientFactoryBean.getTarget();
FeignContext feignContext = context.getBean(FeignContext.class);
Assertions.assertNotNull(feignBuilderCaptor.getValue());
Feign.Builder builder = feignBuilderCaptor.getValue();
Feign.Builder builder = clientFactoryBean.feign(feignContext);
assertFeignBuilderField(builder, "logLevel", Logger.Level.BASIC);
assertFeignBuilderField(builder, "decode404", true);
assertFeignBuilderField(builder, "closeAfterDecode", false);
@@ -122,41 +93,16 @@ class FeignBuilderCustomizerTests {
context.close();
}
@ParameterizedTest(name = "should use custom HttpClient with config: {0}")
@MethodSource("testConfiguration")
void testBuildCustomizerWithCustomHttpClient(Class configClass) {
ArgumentCaptor<Feign.Builder> feignBuilderCaptor = ArgumentCaptor.forClass(Feign.Builder.class);
doCallRealMethod().when(targeterSpy).target(any(), feignBuilderCaptor.capture(), any(), any());
Client customClientMock = mock(Client.class);
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(configClass);
FeignClientFactoryBean clientFactoryBean = context.getBean(FeignClientFactoryBean.class);
clientFactoryBean.addCustomizer(builder -> builder.client(customClientMock));
clientFactoryBean.getTarget();
Assertions.assertNotNull(feignBuilderCaptor.getValue());
Feign.Builder builder = feignBuilderCaptor.getValue();
assertFeignBuilderField(builder, "client", customClientMock);
context.close();
}
private static FeignClientFactoryBean defaultFeignClientFactoryBean(String url) {
private static FeignClientFactoryBean defaultFeignClientFactoryBean() {
FeignClientFactoryBean feignClientFactoryBean = new FeignClientFactoryBean();
feignClientFactoryBean.setContextId("test");
feignClientFactoryBean.setName("test");
feignClientFactoryBean.setType(FeignClientFactoryTests.TestType.class);
feignClientFactoryBean.setPath("");
if (url != null) {
feignClientFactoryBean.setUrl(url);
}
feignClientFactoryBean.setUrl("http://some.absolute.url");
return feignClientFactoryBean;
}
private static Stream<Class> testConfiguration() {
return Stream.of(SampleConfiguration3.class, LoadBalancedSampleConfiguration.class);
}
@Configuration(proxyBeanMethods = false)
@Import(FeignClientsConfiguration.class)
protected static class SampleConfiguration2 {
@@ -183,12 +129,7 @@ class FeignBuilderCustomizerTests {
@Bean
FeignClientFactoryBean feignClientFactoryBean() {
return defaultFeignClientFactoryBean("http://some.absolute.url");
}
@Bean
Targeter targeter() {
return targeterSpy;
return defaultFeignClientFactoryBean();
}
}
@@ -226,29 +167,7 @@ class FeignBuilderCustomizerTests {
@Bean
FeignClientFactoryBean feignClientFactoryBean() {
return defaultFeignClientFactoryBean("http://some.absolute.url");
}
@Bean
Targeter targeter() {
return targeterSpy;
}
@Bean
Client client() {
return defaultClient;
}
}
@Configuration(proxyBeanMethods = false)
@Import(SampleConfiguration3.class)
protected static class LoadBalancedSampleConfiguration {
@Primary
@Bean
FeignClientFactoryBean feignClientFactoryBean() {
return defaultFeignClientFactoryBean(null);
return defaultFeignClientFactoryBean();
}
}
@@ -32,8 +32,6 @@ import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.servlet.http.HttpServletRequest;
import feign.Capability;
import feign.Feign;
import feign.InvocationHandlerFactory;
@@ -47,6 +45,7 @@ import feign.codec.EncodeException;
import feign.codec.Encoder;
import feign.codec.ErrorDecoder;
import feign.micrometer.MicrometerCapability;
import jakarta.servlet.http.HttpServletRequest;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.condition.DisabledForJreRange;
import org.junit.jupiter.api.condition.JRE;
@@ -48,8 +48,9 @@ import static org.springframework.boot.test.context.SpringBootTest.WebEnvironmen
* @author Olga Maciaszek-Sharma
*/
@SpringBootTest(classes = FeignHttpClientUrlTestsWithRetryableLoadBalancer.TestConfig.class,
webEnvironment = DEFINED_PORT, value = { "spring.application.name=feignclienturlwithretryableloadbalancertest",
"feign.hystrix.enabled=false", "feign.okhttp.enabled=false" })
webEnvironment = DEFINED_PORT,
value = { "spring.application.name=feignclienturlwithretryableloadbalancertest", "feign.hystrix.enabled=false",
"feign.okhttp.enabled=false" })
@DirtiesContext
class FeignHttpClientUrlTestsWithRetryableLoadBalancer {
@@ -21,9 +21,8 @@ import java.util.Objects;
import java.util.UUID;
import java.util.function.Function;
import javax.servlet.http.HttpServletRequest;
import feign.RequestInterceptor;
import jakarta.servlet.http.HttpServletRequest;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.ObjectProvider;
@@ -1,78 +0,0 @@
/*
* Copyright 2013-2022 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.circuitbreaker;
import feign.Target;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.openfeign.CircuitBreakerNameResolver;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* @author Ryan Baxter
*/
public class CircuitBreakerAutoConfigurationTests {
@SpringBootTest(classes = CircuitBreakerTests.Application.class,
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
value = { "spring.application.name=springcircuittest", "spring.jmx.enabled=false",
"feign.circuitbreaker.enabled=true" })
@Nested
class DefaultNamingStrategy {
@Autowired
CircuitBreakerNameResolver nameResolver;
@Test
public void assertDefaultNamingStrategy() throws Exception {
Target target = mock(Target.class);
when(target.type()).thenReturn(CircuitBreakerTests.TestClientWithFactory.class);
assertThat(nameResolver.resolveCircuitBreakerName("foo", target,
CircuitBreakerTests.TestClientWithFactory.class.getMethod("getHello")))
.isEqualTo("TestClientWithFactory#getHello()");
}
}
@SpringBootTest(classes = CircuitBreakerTests.Application.class,
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
value = { "spring.application.name=springcircuittest", "spring.jmx.enabled=false",
"feign.circuitbreaker.enabled=true", "feign.circuitbreaker.alphanumeric-ids.enabled=true" })
@Nested
class AlphanumericNamingStrategy {
@Autowired
CircuitBreakerNameResolver nameResolver;
@Test
public void assertAlphanumericNamingStrategy() throws Exception {
Target target = mock(Target.class);
when(target.type()).thenReturn(CircuitBreakerTests.TestClientWithFactory.class);
assertThat(nameResolver.resolveCircuitBreakerName("foo", target,
CircuitBreakerTests.TestClientWithFactory.class.getMethod("getHello")))
.isEqualTo("TestClientWithFactorygetHello");
}
}
}
@@ -16,7 +16,6 @@
package org.springframework.cloud.openfeign.circuitbreaker;
import java.io.IOException;
import java.util.function.Function;
import org.apache.commons.logging.Log;
@@ -48,13 +47,13 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
* @author Spencer Gibb
*/
@SpringBootTest(classes = CircuitBreakerTests.Application.class, webEnvironment = WebEnvironment.DEFINED_PORT, value = {
"spring.application.name=springcircuittest", "spring.jmx.enabled=false", "feign.circuitbreaker.enabled=true" })
@SpringBootTest(classes = CircuitBreakerTests.Application.class, webEnvironment = WebEnvironment.DEFINED_PORT,
value = { "spring.application.name=springcircuittest", "spring.jmx.enabled=false",
"feign.circuitbreaker.enabled=true" })
@DirtiesContext
class CircuitBreakerTests {
@@ -64,9 +63,6 @@ class CircuitBreakerTests {
@Autowired
TestClient testClient;
@Autowired
ExceptionClient exceptionClient;
@Autowired
TestClientWithFactory testClientWithFactory;
@@ -113,17 +109,6 @@ class CircuitBreakerTests {
assertThat(testClientWithFactory.getException()).isEqualTo("Fixed response");
}
@Test
void testRuntimeExceptionUnwrapped() {
assertThatExceptionOfType(UnsupportedOperationException.class)
.isThrownBy(() -> exceptionClient.getRuntimeException());
}
@Test
void testCheckedExceptionWrapped() {
assertThatExceptionOfType(IllegalStateException.class).isThrownBy(() -> exceptionClient.getCheckedException());
}
@FeignClient(name = "test", url = "http://localhost:${server.port}/", fallback = Fallback.class)
protected interface TestClient {
@@ -135,18 +120,6 @@ class CircuitBreakerTests {
}
@FeignClient(name = "exceptionClient", url = "http://localhost:${server.port}/",
fallbackFactory = ExceptionThrowingFallbackFactory.class)
protected interface ExceptionClient {
@GetMapping("/runtimeException")
Hello getRuntimeException();
@GetMapping("/runtimeException")
Hello getCheckedException() throws IOException;
}
@Component
static class Fallback implements TestClient {
@@ -184,25 +157,6 @@ class CircuitBreakerTests {
}
static class ExceptionThrowingFallbackFactory implements FallbackFactory<ExceptionClient> {
@Override
public ExceptionClient create(Throwable cause) {
return new ExceptionClient() {
@Override
public Hello getRuntimeException() {
throw new UnsupportedOperationException("Not implemented!");
}
@Override
public Hello getCheckedException() throws IOException {
throw new IOException();
}
};
}
}
static class FallbackWithFactory implements TestClientWithFactory {
@Override
@@ -220,7 +174,7 @@ class CircuitBreakerTests {
@Configuration(proxyBeanMethods = false)
@EnableAutoConfiguration
@RestController
@EnableFeignClients(clients = { TestClient.class, TestClientWithFactory.class, ExceptionClient.class })
@EnableFeignClients(clients = { TestClient.class, TestClientWithFactory.class })
@Import(NoSecurityConfiguration.class)
protected static class Application implements TestClient {
@@ -272,11 +226,6 @@ class CircuitBreakerTests {
return new TestFallbackFactory();
}
@Bean
ExceptionThrowingFallbackFactory exceptionThrowingFallbackFactory() {
return new ExceptionThrowingFallbackFactory();
}
}
}
@@ -65,9 +65,9 @@ import static org.mockito.Mockito.when;
* Commons project, so here we are only testing the interactions between
* {@link FeignBlockingLoadBalancerClient} and its delegates.
*
* @author Olga Maciaszek-Sharma
* @see <a href=
* "https://github.com/spring-cloud/spring-cloud-commons/blob/main/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/blocking/client/BlockingLoadBalancerClientTests.java">BlockingLoadBalancerClientTests</a>
* @author Olga Maciaszek-Sharma
*/
@ExtendWith(MockitoExtension.class)
class FeignBlockingLoadBalancerClientTests {
@@ -69,9 +69,9 @@ import static org.mockito.Mockito.when;
* Commons project, so here we are only testing the interactions between
* {@link RetryableFeignBlockingLoadBalancerClient} and its delegates.
*
* @author Olga Maciaszek-Sharma
* @see <a href=
* "https://github.com/spring-cloud/spring-cloud-commons/blob/main/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/blocking/client/BlockingLoadBalancerClientTests.java">BlockingLoadBalancerClientTests</a>
* @author Olga Maciaszek-Sharma
*/
@ExtendWith(MockitoExtension.class)
class RetryableFeignBlockingLoadBalancerClientTests {
@@ -16,8 +16,7 @@
package org.springframework.cloud.openfeign.security;
import javax.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequest;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
@@ -16,8 +16,7 @@
package org.springframework.cloud.openfeign.security;
import javax.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequest;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
@@ -78,9 +78,7 @@ import static org.junit.jupiter.api.Assumptions.assumeTrue;
* @author Olga Maciaszek-Sharma
* @author Szymon Linowski
* @author Sam Kruglov
* @author Bhavya Agrawal
**/
*/
class SpringMvcContractTests {
private static final Class<?> EXECUTABLE_TYPE;
@@ -173,39 +171,6 @@ class SpringMvcContractTests {
assertThat(data.indexToName().get(0).iterator().next()).isEqualTo("id");
}
@Test
void testProcessAnnotations_SimpleNoPath() throws Exception {
Method method = TestTemplate_Simple.class.getDeclaredMethod("getTest");
MethodMetadata data = contract.parseAndValidateMetadata(method.getDeclaringClass(), method);
assertThat(data.template().url()).isEqualTo("/");
assertThat(data.template().method()).isEqualTo("GET");
assertThat(data.template().headers().get("Accept").iterator().next())
.isEqualTo(MediaType.APPLICATION_JSON_VALUE);
}
@Test
void testProcessAnnotations_SimplePathIsOnlyASlash() throws Exception {
Method method = TestTemplate_Simple.class.getDeclaredMethod("getSlashPath", String.class);
MethodMetadata data = contract.parseAndValidateMetadata(method.getDeclaringClass(), method);
assertThat(data.template().url()).isEqualTo("/?id=" + "{id}");
assertThat(data.template().method()).isEqualTo("GET");
assertThat(data.template().headers().get("Accept").iterator().next())
.isEqualTo(MediaType.APPLICATION_JSON_VALUE);
}
@Test
void testProcessAnnotations_MissingLeadingSlashInPath() throws Exception {
Method method = TestTemplate_Simple.class.getDeclaredMethod("getTestNoLeadingSlash", String.class);
MethodMetadata data = contract.parseAndValidateMetadata(method.getDeclaringClass(), method);
assertThat(data.template().url()).isEqualTo("/test?name=" + "{name}");
assertThat(data.template().method()).isEqualTo("GET");
assertThat(data.template().headers().get("Accept").iterator().next())
.isEqualTo(MediaType.APPLICATION_JSON_VALUE);
}
@Test
void testProcessAnnotations_SimpleGetMapping() throws Exception {
Method method = TestTemplate_Simple.class.getDeclaredMethod("getMappingTest", String.class);
@@ -651,12 +616,6 @@ class SpringMvcContractTests {
@PostMapping(produces = MediaType.APPLICATION_JSON_VALUE)
TestObject postMappingTest(@RequestBody TestObject object);
@GetMapping(value = "/", produces = MediaType.APPLICATION_JSON_VALUE)
ResponseEntity<TestObject> getSlashPath(@RequestParam("id") String id);
@GetMapping(path = "test", produces = MediaType.APPLICATION_JSON_VALUE)
ResponseEntity<TestObject> getTestNoLeadingSlash(@RequestParam("name") String name);
}
@RequestMapping("/prepend/{classId}")
@@ -32,13 +32,12 @@ import java.util.Optional;
import java.util.UUID;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.Part;
import feign.Client;
import feign.Logger;
import feign.RequestInterceptor;
import feign.codec.EncodeException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.Part;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
+2 -2
View File
@@ -6,11 +6,11 @@
<parent>
<artifactId>spring-cloud-dependencies-parent</artifactId>
<groupId>org.springframework.cloud</groupId>
<version>3.1.3</version>
<version>4.0.0-M1</version>
<relativePath/>
</parent>
<artifactId>spring-cloud-openfeign-dependencies</artifactId>
<version>3.1.3</version>
<version>4.0.0-M1</version>
<packaging>pom</packaging>
<name>spring-cloud-openfeign-dependencies</name>
<description>Spring Cloud OpenFeign Dependencies</description>
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-openfeign</artifactId>
<version>3.1.3</version>
<version>4.0.0-M1</version>
<relativePath>..</relativePath>
</parent>
<artifactId>spring-cloud-starter-openfeign</artifactId>