diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClient.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClient.java
index 365d76b2..422fc4f9 100644
--- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClient.java
+++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClient.java
@@ -63,6 +63,11 @@ public @interface FeignClient {
*/
String url() default "";
+ /**
+ * Whether 404s should be decoded instead of throwing FeignExceptions
+ */
+ boolean decode404() default false;
+
/**
* A custom @Configuration for the feign client. Can contain override
* @Bean definition for the pieces that make up the client, for instance
diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClientFactoryBean.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClientFactoryBean.java
index 8124201b..c024f875 100644
--- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClientFactoryBean.java
+++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClientFactoryBean.java
@@ -55,6 +55,8 @@ class FeignClientFactoryBean implements FactoryBean, InitializingBean, A
private String url;
+ private boolean decode404;
+
private ApplicationContext context;
@Override
@@ -105,6 +107,10 @@ class FeignClientFactoryBean implements FactoryBean, InitializingBean, A
builder.requestInterceptors(requestInterceptors.values());
}
+ if (decode404) {
+ builder.decode404();
+ }
+
return builder;
}
diff --git a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClientsRegistrar.java b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClientsRegistrar.java
index e5496024..f1cdf717 100644
--- a/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClientsRegistrar.java
+++ b/spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/feign/FeignClientsRegistrar.java
@@ -173,6 +173,7 @@ public class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar,
definition.addPropertyValue("url", getUrl(attributes));
definition.addPropertyValue("name", getServiceId(attributes));
definition.addPropertyValue("type", className);
+ definition.addPropertyValue("decode404", attributes.get("decode404"));
definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
String beanName = StringUtils
diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/SpringDecoderTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/SpringDecoderTests.java
index 53c852ea..b718b3e3 100644
--- a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/SpringDecoderTests.java
+++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/SpringDecoderTests.java
@@ -43,6 +43,7 @@ import org.springframework.web.bind.annotation.RestController;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
/**
* @author Spencer Gibb
@@ -66,7 +67,12 @@ public class SpringDecoderTests extends FeignClientFactoryBean {
}
public TestClient testClient() {
+ return testClient(false);
+ }
+
+ public TestClient testClient(boolean decode404) {
setType(this.getClass());
+ setDecode404(decode404);
return feign(factory).target(TestClient.class, "http://localhost:" + this.port);
}
@@ -120,6 +126,13 @@ public class SpringDecoderTests extends FeignClientFactoryBean {
testClient().getNotFound();
}
+ @Test
+ public void testDecodes404() {
+ final ResponseEntity response = testClient(true).getNotFound();
+ assertNotNull("response was null", response);
+ assertNull("response body was not null", response.getBody());
+ }
+
@Data
@AllArgsConstructor
@NoArgsConstructor
diff --git a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/valid/FeignClientTests.java b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/valid/FeignClientTests.java
index 22fbe7dc..9c382685 100644
--- a/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/valid/FeignClientTests.java
+++ b/spring-cloud-netflix-core/src/test/java/org/springframework/cloud/netflix/feign/valid/FeignClientTests.java
@@ -20,6 +20,7 @@ import static org.hamcrest.Matchers.instanceOf;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
@@ -90,6 +91,9 @@ public class FeignClientTests {
@Autowired
private TestClientServiceId testClientServiceId;
+ @Autowired
+ private DecodingTestClient decodingTestClient;
+
@Autowired
private Client feignClient;
@@ -149,14 +153,21 @@ public class FeignClientTests {
Hello getHello();
}
+ @FeignClient(name = "localapp2", decode404 = true)
+ protected interface DecodingTestClient {
+ @RequestMapping(method = RequestMethod.GET, value = "/notFound")
+ ResponseEntity notFound();
+ }
+
@Configuration
@EnableAutoConfiguration
@RestController
- @EnableFeignClients(clients = {TestClientServiceId.class, TestClient.class},
+ @EnableFeignClients(clients = {TestClientServiceId.class, TestClient.class, DecodingTestClient.class},
defaultConfiguration = TestDefaultFeignConfig.class)
@RibbonClients({
@RibbonClient(name = "localapp", configuration = LocalRibbonClientConfiguration.class),
- @RibbonClient(name = "localapp1", configuration = LocalRibbonClientConfiguration.class)
+ @RibbonClient(name = "localapp1", configuration = LocalRibbonClientConfiguration.class),
+ @RibbonClient(name = "localapp2", configuration = LocalRibbonClientConfiguration.class)
})
protected static class Application {
@@ -204,6 +215,11 @@ public class FeignClientTests {
return ResponseEntity.ok().build();
}
+ @RequestMapping(method = RequestMethod.GET, value = "/notFound")
+ ResponseEntity notFound() {
+ return ResponseEntity.status(HttpStatus.NOT_FOUND).body((String)null);
+ }
+
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class).properties(
"spring.application.name=feignclienttest",
@@ -299,6 +315,14 @@ public class FeignClientTests {
assertEquals("status code was wrong", HttpStatus.OK, response.getStatusCode());
}
+ @Test
+ public void testDecodeNotFound() {
+ ResponseEntity response = decodingTestClient.notFound();
+ assertNotNull("response was null", response);
+ assertEquals("status code was wrong", HttpStatus.NOT_FOUND, response.getStatusCode());
+ assertNull("response body was not null", response.getBody());
+ }
+
@Data
@AllArgsConstructor
@NoArgsConstructor