SpringDecoder.java

package cn.home1.oss.lib.test;

import com.google.common.collect.Lists;

import feign.FeignException;
import feign.Response;
import feign.codec.DecodeException;
import feign.codec.Decoder;

import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.ObjectFactory;
import org.springframework.boot.autoconfigure.web.HttpMessageConverters;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.web.client.HttpMessageConverterExtractor;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/*
 * @author Spencer Gibb
 */
public class SpringDecoder implements Decoder {

  private final ObjectFactory<HttpMessageConverters> messageConverters;

  public SpringDecoder(final ObjectFactory<HttpMessageConverters> messageConverters) {
    this.messageConverters = messageConverters;
  }

  @Override
  public Object decode(final Response response, final Type type) throws IOException, FeignException {
    if (type instanceof Class || type instanceof ParameterizedType) {
      @SuppressWarnings({"unchecked", "rawtypes"})
      final HttpMessageConverterExtractor<?> extractor =
        new HttpMessageConverterExtractor(type, this.messageConverters.getObject().getConverters());

      return extractor.extractData(new FeignResponseAdapter(response));
    }
    throw new DecodeException("type is not an instance of Class or ParameterizedType: " + type);
  }


  @Slf4j
  private static class FeignResponseAdapter implements ClientHttpResponse {

    private final Response response;

    FeignResponseAdapter(final Response response) {
      this.response = response;
    }

    @Override
    public HttpStatus getStatusCode() throws IOException {
      return HttpStatus.valueOf(this.response.status());
    }

    @Override
    public int getRawStatusCode() throws IOException {
      return this.response.status();
    }

    @Override
    public String getStatusText() throws IOException {
      return this.response.reason();
    }

    @Override
    public void close() {
      try {
        this.response.body().close();
      } catch (final IOException ex) {
        // Ignore exception on close...
        log.debug("error close feign response body.", ex);
      }
    }

    @Override
    public InputStream getBody() throws IOException {
      return this.response.body().asInputStream();
    }

    @Override
    public HttpHeaders getHeaders() {
      final HttpHeaders responseHeaders = new HttpHeaders();
      response.headers().entrySet().stream() //
        .forEach(entry -> responseHeaders.put(entry.getKey(), Lists.newArrayList(entry.getValue())));
      return responseHeaders;
    }
  }
}