View Javadoc
1   /*
2    * Licensed under the Apache License, Version 2.0 (the "License");
3    * you may not use this file except in compliance with the License.
4    * You may obtain a copy of the License at
5    *
6    *     http://www.apache.org/licenses/LICENSE-2.0
7    *
8    * Unless required by applicable law or agreed to in writing, software
9    * distributed under the License is distributed on an "AS IS" BASIS,
10   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11   * See the License for the specific language governing permissions and
12   * limitations under the License.
13   */
14  package org.gbif.ws.client;
15  
16  import java.io.IOException;
17  import java.lang.reflect.Type;
18  import java.nio.charset.StandardCharsets;
19  
20  import org.springframework.http.HttpHeaders;
21  import org.springframework.http.HttpStatus;
22  import org.springframework.http.MediaType;
23  import org.springframework.util.StringUtils;
24  
25  import com.fasterxml.jackson.databind.ObjectMapper;
26  
27  import feign.FeignException;
28  import feign.Response;
29  import feign.Util;
30  import feign.codec.DecodeException;
31  import feign.codec.Decoder;
32  import feign.jackson.JacksonDecoder;
33  
34  public class ClientDecoder implements Decoder {
35  
36    private final JacksonDecoder jacksonDecoder;
37  
38    public ClientDecoder(ObjectMapper objectMapper) {
39      this.jacksonDecoder = new JacksonDecoder(objectMapper);
40    }
41  
42    @Override
43    public Object decode(Response response, Type type) throws IOException, FeignException {
44      HttpStatus responseStatus = HttpStatus.resolve(response.status());
45  
46      if (responseStatus == HttpStatus.NOT_FOUND || responseStatus == HttpStatus.NO_CONTENT) {
47        return null;
48      } else if (responseStatus != null && responseStatus.isError()) {
49        throw new DecodeException(response.status(), response.toString(), response.request());
50      }
51  
52      MediaType contentType = getContentType(response);
53      if (MediaType.APPLICATION_JSON.equalsTypeAndSubtype(contentType)) {
54        return jacksonDecoder.decode(response, type);
55      } else if (MediaType.TEXT_PLAIN.equalsTypeAndSubtype(contentType)) {
56        return Util.toString(response.body().asReader(StandardCharsets.UTF_8));
57      } else if (MediaType.APPLICATION_OCTET_STREAM.equalsTypeAndSubtype(contentType)) {
58        return Util.toByteArray(response.body().asInputStream());
59      } else if (byte[].class.equals(type)) {
60        return Util.toByteArray(response.body().asInputStream());
61      } else {
62        throw new DecodeException(response.status(), "Unsupported response type", response.request());
63      }
64    }
65  
66    /**
67     * Gets the first MediaType listed in the Content-Type header.
68     */
69    private static MediaType getContentType(Response response) {
70      return response.headers().get(HttpHeaders.CONTENT_TYPE).stream()
71          .findFirst()
72          .filter(StringUtils::hasLength)
73          .map(MediaType::parseMediaType)
74          .orElse(null);
75    }
76  }