diff --git a/core/src/main/java/feign/optionals/OptionalDecoder.java b/core/src/main/java/feign/optionals/OptionalDecoder.java index 06d9c76c3..90d0d03a7 100644 --- a/core/src/main/java/feign/optionals/OptionalDecoder.java +++ b/core/src/main/java/feign/optionals/OptionalDecoder.java @@ -39,7 +39,7 @@ public Object decode(Response response, Type type) throws IOException { return Optional.empty(); } Type enclosedType = Util.resolveLastTypeParameter(type, Optional.class); - return Optional.of(delegate.decode(response, enclosedType)); + return Optional.ofNullable(delegate.decode(response, enclosedType)); } static boolean isOptional(Type type) { diff --git a/core/src/test/java/feign/optionals/OptionalDecoderTests.java b/core/src/test/java/feign/optionals/OptionalDecoderTests.java index a7b8d3836..60a44e345 100644 --- a/core/src/test/java/feign/optionals/OptionalDecoderTests.java +++ b/core/src/test/java/feign/optionals/OptionalDecoderTests.java @@ -27,7 +27,10 @@ public class OptionalDecoderTests { interface OptionalInterface { @RequestLine("GET /") - Optional get(); + Optional getAsOptional(); + + @RequestLine("GET /") + String get(); } @Test @@ -41,8 +44,8 @@ public void simple404OptionalTest() throws IOException, InterruptedException { .decoder(new OptionalDecoder(new Decoder.Default())) .target(OptionalInterface.class, server.url("/").toString()); - assertThat(api.get().isPresent()).isFalse(); - assertThat(api.get().get()).isEqualTo("foo"); + assertThat(api.getAsOptional().isPresent()).isFalse(); + assertThat(api.getAsOptional().get()).isEqualTo("foo"); } @Test @@ -54,6 +57,45 @@ public void simple204OptionalTest() throws IOException, InterruptedException { .decoder(new OptionalDecoder(new Decoder.Default())) .target(OptionalInterface.class, server.url("/").toString()); - assertThat(api.get().isPresent()).isFalse(); + assertThat(api.getAsOptional().isPresent()).isFalse(); + } + + @Test + public void test200WithOptionalString() throws IOException, InterruptedException { + final MockWebServer server = new MockWebServer(); + server.enqueue(new MockResponse().setResponseCode(200).setBody("foo")); + + final OptionalInterface api = Feign.builder() + .decoder(new OptionalDecoder(new Decoder.Default())) + .target(OptionalInterface.class, server.url("/").toString()); + + Optional response = api.getAsOptional(); + + assertThat(response.isPresent()).isTrue(); + assertThat(response).isEqualTo(Optional.of("foo")); + } + + @Test + public void test200WhenResponseBodyIsNull() throws IOException, InterruptedException { + final MockWebServer server = new MockWebServer(); + server.enqueue(new MockResponse().setResponseCode(200)); + + final OptionalInterface api = Feign.builder() + .decoder(new OptionalDecoder(((response, type) -> null))) + .target(OptionalInterface.class, server.url("/").toString()); + + assertThat(api.getAsOptional().isPresent()).isFalse(); + } + + @Test + public void test200WhenDecodingNoOptional() throws IOException, InterruptedException { + final MockWebServer server = new MockWebServer(); + server.enqueue(new MockResponse().setResponseCode(200).setBody("foo")); + + final OptionalInterface api = Feign.builder() + .decoder(new OptionalDecoder(new Decoder.Default())) + .target(OptionalInterface.class, server.url("/").toString()); + + assertThat(api.get()).isEqualTo("foo"); } }