All Downloads are FREE. Search and download functionalities are using the official Maven repository.

feign.InvocationContext Maven / Gradle / Ivy

/*
 * Copyright 2012-2023 The Feign Authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 * in compliance with the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package feign;

import static feign.FeignException.errorReading;
import static feign.Util.ensureClosed;
import feign.codec.DecodeException;
import feign.codec.Decoder;
import feign.codec.ErrorDecoder;
import java.io.IOException;
import java.lang.reflect.Type;

public class InvocationContext {
  private static final long MAX_RESPONSE_BUFFER_SIZE = 8192L;
  private final String configKey;
  private final Decoder decoder;
  private final ErrorDecoder errorDecoder;
  private final boolean dismiss404;
  private final boolean closeAfterDecode;
  private final boolean decodeVoid;
  private final Response response;
  private final Type returnType;

  InvocationContext(String configKey, Decoder decoder, ErrorDecoder errorDecoder,
      boolean dismiss404, boolean closeAfterDecode, boolean decodeVoid, Response response,
      Type returnType) {
    this.configKey = configKey;
    this.decoder = decoder;
    this.errorDecoder = errorDecoder;
    this.dismiss404 = dismiss404;
    this.closeAfterDecode = closeAfterDecode;
    this.decodeVoid = decodeVoid;
    this.response = response;
    this.returnType = returnType;
  }

  public Decoder decoder() {
    return decoder;
  }

  public Type returnType() {
    return returnType;
  }

  public Response response() {
    return response;
  }

  public Object proceed() throws Exception {
    if (returnType == Response.class) {
      return disconnectResponseBodyIfNeeded(response);
    }

    try {
      final boolean shouldDecodeResponseBody =
          (response.status() >= 200 && response.status() < 300)
              || (response.status() == 404 && dismiss404
                  && !isVoidType(returnType));

      if (!shouldDecodeResponseBody) {
        throw decodeError(configKey, response);
      }

      if (isVoidType(returnType) && !decodeVoid) {
        ensureClosed(response.body());
        return null;
      }

      Class rawType = Types.getRawType(returnType);
      if (TypedResponse.class.isAssignableFrom(rawType)) {
        Type bodyType = Types.resolveLastTypeParameter(returnType, TypedResponse.class);
        return TypedResponse.builder(response)
            .body(decode(response, bodyType))
            .build();
      }

      return decode(response, returnType);
    } finally {
      if (closeAfterDecode) {
        ensureClosed(response.body());
      }
    }
  }

  private static Response disconnectResponseBodyIfNeeded(Response response) throws IOException {
    final boolean shouldDisconnectResponseBody = response.body() != null
        && response.body().length() != null
        && response.body().length() <= MAX_RESPONSE_BUFFER_SIZE;
    if (!shouldDisconnectResponseBody) {
      return response;
    }

    try {
      final byte[] bodyData = Util.toByteArray(response.body().asInputStream());
      return response.toBuilder().body(bodyData).build();
    } finally {
      ensureClosed(response.body());
    }
  }

  private Object decode(Response response, Type returnType) {
    try {
      return decoder.decode(response, returnType);
    } catch (final FeignException e) {
      throw e;
    } catch (final RuntimeException e) {
      throw new DecodeException(response.status(), e.getMessage(), response.request(), e);
    } catch (IOException e) {
      throw errorReading(response.request(), response, e);
    }
  }

  private Exception decodeError(String methodKey, Response response) {
    try {
      return errorDecoder.decode(methodKey, response);
    } finally {
      ensureClosed(response.body());
    }
  }

  private boolean isVoidType(Type returnType) {
    return returnType == Void.class
        || returnType == void.class
        || returnType.getTypeName().equals("kotlin.Unit");
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy