Removing exception wrapping adds flexibility to the interplay of Decoder and ErrorDecoder:
A Decoder can now delegate to an ErrorDecoder and the original ErrorDecoder exception gets
thrown rather than a Feign-specific DecodeException. An example use-case is a Jackson/Gson
implementation of special 404-handling of Optional<Foo> methods: when the Feign client has
decode404() enabled, then the Decoder is in charge of dispatching 404 to Optional#absent
where applicable, or to a delegate ErrorDecoder otherwise; consistent exception handling
requires that the exception produced by the ErrorDecoder does not wrapped.
This adds the `Feign.Builder.decode404()` flag which indicates decoders
should process responses with 404 status. It also changes all
first-party decoders (like gson) to return well-known empty values by
default. Further customization is possible by wrapping or creating a
custom decoder.
Prior to this change, we used custom invocation handlers as the way to
add fallback values based on exception or return status. `feign-hystrix`
uses this to return `HystrixCommand<X>`, but the general pattern applies
to anything that has a type representing both success and failure, such
as `Try<X>` or `Observable<X>`.
As we define it here, 404 status is not a retry or fallback policy, it
is just empty semantics. By limiting Feign's special processing to 404,
we gain a lot with very little supporting code.
If instead we opened all codes, Feign could easily turn bad request,
redirect, or server errors silently to null. This sort of configuration
issue is hard to troubleshoot. 404 -> empty is a very safe policy vs
all codes.
Moreover, we don't create a cliff, where folks seeking fallback policy
eventually realize they can't if only given a response code. Fallback
systems like Hystrix address exceptions that occur before or in lieu of
a response. By special-casing 404, we avoid a slippery slope of half-
implementing Hystrix.
Finally, 404 handling has been commonly requested: it has a clear use-
case, and through that value. This design supports that without breaking
compatibility, or impacting existing integrations such as Hystrix or
Ribbon.
See #238#287
In unsuccessful scenarios, such as redirects, error handling converts a
`Response` into an exception. When a user defines a return type as
`Response`, we can assume they will want access to things like headers
even in an error scenario.
See #249
When log level is full, the response body is rebuffered. The Apache
client had a bug where it allowed `toInputStream` to return null. This
fixes that bug and backfills tests for the other two clients.
Fixes#255
InputStream.available isn't a reliable api. This uses an alternative
approach, which is to read the first byte to see if it is present. This
allows us to continue to avoid "No content to map due to end-of-input"
errors, but in a more supportable way.
Fixes#250
No content to map due to end-of-input when decoding empty returns using JacksonDecoder.
Added UnitTests to show JacksonDecoder error. Added unit test to GsonDecoder to verify behavior is as expected.
Added a check for available inputStream data before trying to read into an Object.
closes#247
Before this change, apis that follow patterns across a service could
only be modeled by copy/paste/find/replace. Especially with a large
count, this is monotonous and error prone.
This change introduces support for base apis via single-inheritance
interfaces. Users ensure their target interface bind any type variables
and as a result have little effort to create boilerplate apis.
Ex.
```java
@Headers("Accept: application/json")
interface BaseApi<V> {
@RequestLine("GET /api/{key}")
V get(@Param("key") String);
@RequestLine("GET /api")
List<V> list();
@Headers("Content-Type: application/json")
@RequestLine("PUT /api/{key}")
void put(@Param("key") String, V value);
}
interface FooApi extends BaseApi<Foo> { }
interface BarApi extends BaseApi<Bar> { }
```
closes#133