Skip to content

Commit

Permalink
add ResponseInterceptor support OpenFeign#1126
Browse files Browse the repository at this point in the history
  • Loading branch information
Fei,Yanke committed Apr 28, 2022
1 parent e1a7028 commit 40db4ba
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 9 deletions.
18 changes: 16 additions & 2 deletions core/src/main/java/feign/Feign.java
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,8 @@ public static class Builder {

private final List<RequestInterceptor> requestInterceptors =
new ArrayList<RequestInterceptor>();
private final List<ResponseInterceptor> responseInterceptors =
new ArrayList<ResponseInterceptor>();
private Logger.Level logLevel = Logger.Level.NONE;
private Contract contract = new Contract.Default();
private Client client = new Client.Default(null, null);
Expand Down Expand Up @@ -227,6 +229,14 @@ public Builder requestInterceptor(RequestInterceptor requestInterceptor) {
return this;
}

/**
* Adds a single response interceptor to the builder.
*/
public Builder responseInterceptor(ResponseInterceptor responseInterceptor) {
this.responseInterceptors.add(responseInterceptor);
return this;
}

/**
* Sets the full set of request interceptors for the builder, overwriting any previous
* interceptors.
Expand Down Expand Up @@ -297,6 +307,9 @@ public Feign build() {
List<RequestInterceptor> requestInterceptors = this.requestInterceptors.stream()
.map(ri -> Capability.enrich(ri, capabilities))
.collect(Collectors.toList());
List<ResponseInterceptor> responseInterceptors = this.responseInterceptors.stream()
.map(ri -> Capability.enrich(ri, capabilities))
.collect(Collectors.toList());
Logger logger = Capability.enrich(this.logger, capabilities);
Contract contract = Capability.enrich(this.contract, capabilities);
Options options = Capability.enrich(this.options, capabilities);
Expand All @@ -307,8 +320,9 @@ public Feign build() {
QueryMapEncoder queryMapEncoder = Capability.enrich(this.queryMapEncoder, capabilities);

SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =
new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger,
logLevel, dismiss404, closeAfterDecode, propagationPolicy, forceDecoding);
new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors,
responseInterceptors,logger, logLevel, dismiss404, closeAfterDecode,
propagationPolicy, forceDecoding);
ParseHandlersByName handlersByName =
new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder,
errorDecoder, synchronousMethodHandlerFactory);
Expand Down
29 changes: 29 additions & 0 deletions core/src/main/java/feign/ResponseInterceptor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package feign;

/**
* Zero or more {@code ResponseInterceptor} may be configured for purposes
* such as verify or modify headers of response, verify the business status of decoded object.
* No guarantees are given with regards to the order that interceptors are applied.
* Once interceptors are applied, {@link ResponseInterceptor#beforeDecode(Response)} is called
* before decode method called, {@link ResponseInterceptor#afterDecode(Object)} is called
* after decode method called.
*/
public interface ResponseInterceptor {

/**
* Called for response before decode, add data on the supplied {@link Response} or doing
* customized logic
*
* @param response
* @return
*/
void beforeDecode(Response response);

/**
* Called for response after decode, add data to decoded object or doing customized logic
*
* @param response
* @return
*/
void afterDecode(Object response);
}
34 changes: 27 additions & 7 deletions core/src/main/java/feign/SynchronousMethodHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ final class SynchronousMethodHandler implements MethodHandler {
private final Client client;
private final Retryer retryer;
private final List<RequestInterceptor> requestInterceptors;
private final List<ResponseInterceptor> responseInterceptors;
private final Logger logger;
private final Logger.Level logLevel;
private final RequestTemplate.Factory buildTemplateFromArgs;
Expand All @@ -48,8 +49,8 @@ final class SynchronousMethodHandler implements MethodHandler {


private SynchronousMethodHandler(Target<?> target, Client client, Retryer retryer,
List<RequestInterceptor> requestInterceptors, Logger logger,
Logger.Level logLevel, MethodMetadata metadata,
List<RequestInterceptor> requestInterceptors, List<ResponseInterceptor> responseInterceptors,
Logger logger, Logger.Level logLevel, MethodMetadata metadata,
RequestTemplate.Factory buildTemplateFromArgs, Options options,
Decoder decoder, ErrorDecoder errorDecoder, boolean dismiss404,
boolean closeAfterDecode, ExceptionPropagationPolicy propagationPolicy,
Expand All @@ -60,6 +61,8 @@ private SynchronousMethodHandler(Target<?> target, Client client, Retryer retrye
this.retryer = checkNotNull(retryer, "retryer for %s", target);
this.requestInterceptors =
checkNotNull(requestInterceptors, "requestInterceptors for %s", target);
this.responseInterceptors =
checkNotNull(responseInterceptors, "responseInterceptors for %s", target);
this.logger = checkNotNull(logger, "logger for %s", target);
this.logLevel = checkNotNull(logLevel, "logLevel for %s", target);
this.metadata = checkNotNull(metadata, "metadata for %s", target);
Expand Down Expand Up @@ -130,9 +133,19 @@ Object executeAndDecode(RequestTemplate template, Options options) throws Throwa
}
long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);

for (ResponseInterceptor interceptor: responseInterceptors) {
interceptor.beforeDecode(response);
}

if (decoder != null) {
Object object = decoder.decode(response, metadata.returnType());

for (ResponseInterceptor interceptor: responseInterceptors) {
interceptor.afterDecode(object);
}

if (decoder != null)
return decoder.decode(response, metadata.returnType());
return object;
}

CompletableFuture<Object> resultFuture = new CompletableFuture<>();
asyncResponseHandler.handleResponse(resultFuture, metadata.configKey(), response,
Expand All @@ -143,7 +156,11 @@ Object executeAndDecode(RequestTemplate template, Options options) throws Throwa
if (!resultFuture.isDone())
throw new IllegalStateException("Response handling not done");

return resultFuture.join();
Object object = resultFuture.join();
for (ResponseInterceptor interceptor: responseInterceptors) {
interceptor.afterDecode(object);
}
return object;
} catch (CompletionException e) {
Throwable cause = e.getCause();
if (cause != null)
Expand Down Expand Up @@ -179,6 +196,7 @@ static class Factory {
private final Client client;
private final Retryer retryer;
private final List<RequestInterceptor> requestInterceptors;
private final List<ResponseInterceptor> responseInterceptors;
private final Logger logger;
private final Logger.Level logLevel;
private final boolean dismiss404;
Expand All @@ -187,11 +205,13 @@ static class Factory {
private final boolean forceDecoding;

Factory(Client client, Retryer retryer, List<RequestInterceptor> requestInterceptors,
List<ResponseInterceptor> responseInterceptors,
Logger logger, Logger.Level logLevel, boolean dismiss404, boolean closeAfterDecode,
ExceptionPropagationPolicy propagationPolicy, boolean forceDecoding) {
this.client = checkNotNull(client, "client");
this.retryer = checkNotNull(retryer, "retryer");
this.requestInterceptors = checkNotNull(requestInterceptors, "requestInterceptors");
this.responseInterceptors = checkNotNull(responseInterceptors, "responseInterceptors");
this.logger = checkNotNull(logger, "logger");
this.logLevel = checkNotNull(logLevel, "logLevel");
this.dismiss404 = dismiss404;
Expand All @@ -206,8 +226,8 @@ public MethodHandler create(Target<?> target,
Options options,
Decoder decoder,
ErrorDecoder errorDecoder) {
return new SynchronousMethodHandler(target, client, retryer, requestInterceptors, logger,
logLevel, md, buildTemplateFromArgs, options, decoder,
return new SynchronousMethodHandler(target, client, retryer, requestInterceptors,
responseInterceptors, logger, logLevel, md, buildTemplateFromArgs, options, decoder,
errorDecoder, dismiss404, closeAfterDecode, propagationPolicy, forceDecoding);
}
}
Expand Down

0 comments on commit 40db4ba

Please sign in to comment.