001/* 002 * Licensed under the Apache License, Version 2.0 (the "License"); 003 * you may not use this file except in compliance with the License. 004 * You may obtain a copy of the License at 005 * 006 * http://www.apache.org/licenses/LICENSE-2.0 007 * 008 * Unless required by applicable law or agreed to in writing, software 009 * distributed under the License is distributed on an "AS IS" BASIS, 010 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 011 * See the License for the specific language governing permissions and 012 * limitations under the License. 013 */ 014package org.gbif.ws.client; 015 016import java.io.IOException; 017import java.lang.reflect.Type; 018import java.nio.charset.StandardCharsets; 019 020import org.springframework.http.HttpHeaders; 021import org.springframework.http.HttpStatus; 022import org.springframework.http.MediaType; 023import org.springframework.util.StringUtils; 024 025import com.fasterxml.jackson.databind.ObjectMapper; 026 027import feign.FeignException; 028import feign.Response; 029import feign.Util; 030import feign.codec.DecodeException; 031import feign.codec.Decoder; 032import feign.jackson.JacksonDecoder; 033 034public class ClientDecoder implements Decoder { 035 036 private final JacksonDecoder jacksonDecoder; 037 038 public ClientDecoder(ObjectMapper objectMapper) { 039 this.jacksonDecoder = new JacksonDecoder(objectMapper); 040 } 041 042 @Override 043 public Object decode(Response response, Type type) throws IOException, FeignException { 044 HttpStatus responseStatus = HttpStatus.resolve(response.status()); 045 046 if (responseStatus == HttpStatus.NOT_FOUND || responseStatus == HttpStatus.NO_CONTENT) { 047 return null; 048 } else if (responseStatus != null && responseStatus.isError()) { 049 throw new DecodeException(response.status(), response.toString(), response.request()); 050 } 051 052 MediaType contentType = getContentType(response); 053 if (MediaType.APPLICATION_JSON.equalsTypeAndSubtype(contentType)) { 054 return jacksonDecoder.decode(response, type); 055 } else if (MediaType.TEXT_PLAIN.equalsTypeAndSubtype(contentType)) { 056 return Util.toString(response.body().asReader(StandardCharsets.UTF_8)); 057 } else if (MediaType.APPLICATION_OCTET_STREAM.equalsTypeAndSubtype(contentType)) { 058 return Util.toByteArray(response.body().asInputStream()); 059 } else if (byte[].class.equals(type)) { 060 return Util.toByteArray(response.body().asInputStream()); 061 } else { 062 throw new DecodeException(response.status(), "Unsupported response type", response.request()); 063 } 064 } 065 066 /** 067 * Gets the first MediaType listed in the Content-Type header. 068 */ 069 private static MediaType getContentType(Response response) { 070 return response.headers().get(HttpHeaders.CONTENT_TYPE).stream() 071 .findFirst() 072 .filter(StringUtils::hasLength) 073 .map(MediaType::parseMediaType) 074 .orElse(null); 075 } 076}