Compare commits

...
8 changed files with 79 additions and 12 deletions
+1 -2
View File
@@ -40,8 +40,7 @@ and binding to the Spring Environment and other Spring programming model idioms.
== Building == Building
:jdkversion: 1.8
:jdkversion: 17
=== Basic Compile and Test === Basic Compile and Test
+1 -1
View File
@@ -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.1.1</version> <version>3.1.2-SNAPSHOT</version>
</parent> </parent>
<artifactId>spring-cloud-openfeign-docs</artifactId> <artifactId>spring-cloud-openfeign-docs</artifactId>
<packaging>jar</packaging> <packaging>jar</packaging>
+2 -2
View File
@@ -4,7 +4,7 @@
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.1.1</version> <version>3.1.2-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>
@@ -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.1.1</spring-cloud-commons.version> <spring-cloud-commons.version>3.1.2-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>
+1 -1
View File
@@ -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.1.1</version> <version>3.1.2-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>
@@ -17,6 +17,7 @@
package org.springframework.cloud.openfeign; package org.springframework.cloud.openfeign;
import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Proxy; import java.lang.reflect.Proxy;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
@@ -29,6 +30,7 @@ import feign.Target;
import org.springframework.cloud.client.circuitbreaker.CircuitBreaker; import org.springframework.cloud.client.circuitbreaker.CircuitBreaker;
import org.springframework.cloud.client.circuitbreaker.CircuitBreakerFactory; 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.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.RequestContextHolder;
@@ -95,15 +97,29 @@ class FeignCircuitBreakerInvocationHandler implements InvocationHandler {
try { try {
return this.fallbackMethodMap.get(method).invoke(fallback, args); return this.fallbackMethodMap.get(method).invoke(fallback, args);
} }
catch (Exception e) { catch (Exception exception) {
throw new IllegalStateException(e); unwrapAndRethrow(exception);
} }
return null;
}; };
return circuitBreaker.run(supplier, fallbackFunction); return circuitBreaker.run(supplier, fallbackFunction);
} }
return circuitBreaker.run(supplier); 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) { private Supplier<Object> asSupplier(final Method method, final Object[] args) {
final RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes(); final RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
return () -> { return () -> {
@@ -16,6 +16,7 @@
package org.springframework.cloud.openfeign.circuitbreaker; package org.springframework.cloud.openfeign.circuitbreaker;
import java.io.IOException;
import java.util.function.Function; import java.util.function.Function;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
@@ -47,6 +48,7 @@ import org.springframework.web.bind.annotation.GetMapping;
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;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/** /**
* @author Spencer Gibb * @author Spencer Gibb
@@ -62,6 +64,9 @@ class CircuitBreakerTests {
@Autowired @Autowired
TestClient testClient; TestClient testClient;
@Autowired
ExceptionClient exceptionClient;
@Autowired @Autowired
TestClientWithFactory testClientWithFactory; TestClientWithFactory testClientWithFactory;
@@ -108,6 +113,17 @@ class CircuitBreakerTests {
assertThat(testClientWithFactory.getException()).isEqualTo("Fixed response"); 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) @FeignClient(name = "test", url = "http://localhost:${server.port}/", fallback = Fallback.class)
protected interface TestClient { protected interface TestClient {
@@ -119,6 +135,18 @@ 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 @Component
static class Fallback implements TestClient { static class Fallback implements TestClient {
@@ -156,6 +184,25 @@ 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 { static class FallbackWithFactory implements TestClientWithFactory {
@Override @Override
@@ -173,7 +220,7 @@ class CircuitBreakerTests {
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
@EnableAutoConfiguration @EnableAutoConfiguration
@RestController @RestController
@EnableFeignClients(clients = { TestClient.class, TestClientWithFactory.class }) @EnableFeignClients(clients = { TestClient.class, TestClientWithFactory.class, ExceptionClient.class })
@Import(NoSecurityConfiguration.class) @Import(NoSecurityConfiguration.class)
protected static class Application implements TestClient { protected static class Application implements TestClient {
@@ -225,6 +272,11 @@ class CircuitBreakerTests {
return new TestFallbackFactory(); return new TestFallbackFactory();
} }
@Bean
ExceptionThrowingFallbackFactory exceptionThrowingFallbackFactory() {
return new ExceptionThrowingFallbackFactory();
}
} }
} }
+2 -2
View File
@@ -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.1.1</version> <version>3.1.2-SNAPSHOT</version>
<relativePath/> <relativePath/>
</parent> </parent>
<artifactId>spring-cloud-openfeign-dependencies</artifactId> <artifactId>spring-cloud-openfeign-dependencies</artifactId>
<version>3.1.1</version> <version>3.1.2-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>
+1 -1
View File
@@ -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.1.1</version> <version>3.1.2-SNAPSHOT</version>
<relativePath>..</relativePath> <relativePath>..</relativePath>
</parent> </parent>
<artifactId>spring-cloud-starter-openfeign</artifactId> <artifactId>spring-cloud-starter-openfeign</artifactId>