Skip to content

Commit

Permalink
Refactor AsyncResponseHandler
Browse files Browse the repository at this point in the history
  • Loading branch information
wplong11 committed Oct 10, 2022
1 parent a20fe95 commit 84becff
Showing 1 changed file with 81 additions and 43 deletions.
124 changes: 81 additions & 43 deletions core/src/main/java/feign/AsyncResponseHandler.java
Expand Up @@ -54,67 +54,105 @@ public AsyncResponseHandler(Level logLevel, Logger logger, Decoder decoder,
this.responseInterceptor = responseInterceptor;
}

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

public void handleResponse(CompletableFuture<Object> resultFuture,
String configKey,
Response response,
Type returnType,
long elapsedTime) {
// copied fairly liberally from SynchronousMethodHandler
boolean shouldClose = true;
try {
resultFuture.complete(
handleResponse(configKey, response, returnType, elapsedTime)
);
} catch (Exception e) {
resultFuture.completeExceptionally(e);
}
}

private Object handleResponse(String configKey,
Response response,
Type returnType,
long elapsedTime) throws Exception {
try {
if (logLevel != Level.NONE) {
response = logger.logAndRebufferResponse(configKey, logLevel, response,
elapsedTime);
response = logAndRebufferResponseIfNeeded(configKey, response, elapsedTime);
if (returnType == Response.class) {
return disconnectResponseBodyIfNeeded(response);
}
if (Response.class == returnType) {
if (response.body() == null) {
resultFuture.complete(response);
} else if (response.body().length() == null
|| response.body().length() > MAX_RESPONSE_BUFFER_SIZE) {
shouldClose = false;
resultFuture.complete(response);
} else {
// Ensure the response body is disconnected
final byte[] bodyData = Util.toByteArray(response.body().asInputStream());
resultFuture.complete(response.toBuilder().body(bodyData).build());
}
} else if (response.status() >= 200 && response.status() < 300) {
if (isVoidType(returnType)) {
resultFuture.complete(null);
} else {
final Object result = decode(response, returnType);
shouldClose = closeAfterDecode;
resultFuture.complete(result);
}
} else if (dismiss404 && response.status() == 404 && !isVoidType(returnType)) {
final Object result = decode(response, returnType);
shouldClose = closeAfterDecode;
resultFuture.complete(result);
} else {
resultFuture.completeExceptionally(errorDecoder.decode(configKey, response));

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

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

return decode(response, returnType);
} catch (final IOException e) {
if (logLevel != Level.NONE) {
logger.logIOException(configKey, logLevel, e, elapsedTime);
}
resultFuture.completeExceptionally(errorReading(response.request(), response, e));
} catch (final Exception e) {
resultFuture.completeExceptionally(e);
throw errorReading(response.request(), response, e);
}
}

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

private Response logAndRebufferResponseIfNeeded(String configKey,
Response response,
long elapsedTime) throws IOException {
if (logLevel == Level.NONE) {
return response;
}

return logger.logAndRebufferResponse(configKey, logLevel, response, elapsedTime);
}

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 {
if (shouldClose) {
ensureClosed(response.body());
}
}

private Object decode(Response response, Type type) throws IOException {
if (isVoidType(type)) {
ensureClosed(response.body());
return null;
}

try {
final Object result = responseInterceptor.aroundDecode(
new InvocationContext(decoder, type, response)
);
if (closeAfterDecode) {
ensureClosed(response.body());
}
return result;
} catch (Exception e) {
ensureClosed(response.body());
throw e;
}

}

Object decode(Response response, Type type) throws IOException {
return responseInterceptor.aroundDecode(new InvocationContext(decoder, type, response));
private Exception decodeError(String methodKey, Response response) {
try {
return errorDecoder.decode(methodKey, response);
} finally {
ensureClosed(response.body());
}
}
}

0 comments on commit 84becff

Please sign in to comment.