Skip to content

Commit 40db4ba

Browse files
author
Fei,Yanke
committed
add ResponseInterceptor support OpenFeign#1126
1 parent e1a7028 commit 40db4ba

3 files changed

Lines changed: 72 additions & 9 deletions

File tree

‎core/src/main/java/feign/Feign.java‎

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ public static class Builder {
9898

9999
private final List<RequestInterceptor> requestInterceptors =
100100
new ArrayList<RequestInterceptor>();
101+
private final List<ResponseInterceptor> responseInterceptors =
102+
new ArrayList<ResponseInterceptor>();
101103
private Logger.Level logLevel = Logger.Level.NONE;
102104
private Contract contract = new Contract.Default();
103105
private Client client = new Client.Default(null, null);
@@ -227,6 +229,14 @@ public Builder requestInterceptor(RequestInterceptor requestInterceptor) {
227229
return this;
228230
}
229231

232+
/**
233+
* Adds a single response interceptor to the builder.
234+
*/
235+
public Builder responseInterceptor(ResponseInterceptor responseInterceptor) {
236+
this.responseInterceptors.add(responseInterceptor);
237+
return this;
238+
}
239+
230240
/**
231241
* Sets the full set of request interceptors for the builder, overwriting any previous
232242
* interceptors.
@@ -297,6 +307,9 @@ public Feign build() {
297307
List<RequestInterceptor> requestInterceptors = this.requestInterceptors.stream()
298308
.map(ri -> Capability.enrich(ri, capabilities))
299309
.collect(Collectors.toList());
310+
List<ResponseInterceptor> responseInterceptors = this.responseInterceptors.stream()
311+
.map(ri -> Capability.enrich(ri, capabilities))
312+
.collect(Collectors.toList());
300313
Logger logger = Capability.enrich(this.logger, capabilities);
301314
Contract contract = Capability.enrich(this.contract, capabilities);
302315
Options options = Capability.enrich(this.options, capabilities);
@@ -307,8 +320,9 @@ public Feign build() {
307320
QueryMapEncoder queryMapEncoder = Capability.enrich(this.queryMapEncoder, capabilities);
308321

309322
SynchronousMethodHandler.Factory synchronousMethodHandlerFactory =
310-
new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors, logger,
311-
logLevel, dismiss404, closeAfterDecode, propagationPolicy, forceDecoding);
323+
new SynchronousMethodHandler.Factory(client, retryer, requestInterceptors,
324+
responseInterceptors,logger, logLevel, dismiss404, closeAfterDecode,
325+
propagationPolicy, forceDecoding);
312326
ParseHandlersByName handlersByName =
313327
new ParseHandlersByName(contract, options, encoder, decoder, queryMapEncoder,
314328
errorDecoder, synchronousMethodHandlerFactory);
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package feign;
2+
3+
/**
4+
* Zero or more {@code ResponseInterceptor} may be configured for purposes
5+
* such as verify or modify headers of response, verify the business status of decoded object.
6+
* No guarantees are given with regards to the order that interceptors are applied.
7+
* Once interceptors are applied, {@link ResponseInterceptor#beforeDecode(Response)} is called
8+
* before decode method called, {@link ResponseInterceptor#afterDecode(Object)} is called
9+
* after decode method called.
10+
*/
11+
public interface ResponseInterceptor {
12+
13+
/**
14+
* Called for response before decode, add data on the supplied {@link Response} or doing
15+
* customized logic
16+
*
17+
* @param response
18+
* @return
19+
*/
20+
void beforeDecode(Response response);
21+
22+
/**
23+
* Called for response after decode, add data to decoded object or doing customized logic
24+
*
25+
* @param response
26+
* @return
27+
*/
28+
void afterDecode(Object response);
29+
}

‎core/src/main/java/feign/SynchronousMethodHandler.java‎

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ final class SynchronousMethodHandler implements MethodHandler {
3636
private final Client client;
3737
private final Retryer retryer;
3838
private final List<RequestInterceptor> requestInterceptors;
39+
private final List<ResponseInterceptor> responseInterceptors;
3940
private final Logger logger;
4041
private final Logger.Level logLevel;
4142
private final RequestTemplate.Factory buildTemplateFromArgs;
@@ -48,8 +49,8 @@ final class SynchronousMethodHandler implements MethodHandler {
4849

4950

5051
private SynchronousMethodHandler(Target<?> target, Client client, Retryer retryer,
51-
List<RequestInterceptor> requestInterceptors, Logger logger,
52-
Logger.Level logLevel, MethodMetadata metadata,
52+
List<RequestInterceptor> requestInterceptors, List<ResponseInterceptor> responseInterceptors,
53+
Logger logger, Logger.Level logLevel, MethodMetadata metadata,
5354
RequestTemplate.Factory buildTemplateFromArgs, Options options,
5455
Decoder decoder, ErrorDecoder errorDecoder, boolean dismiss404,
5556
boolean closeAfterDecode, ExceptionPropagationPolicy propagationPolicy,
@@ -60,6 +61,8 @@ private SynchronousMethodHandler(Target<?> target, Client client, Retryer retrye
6061
this.retryer = checkNotNull(retryer, "retryer for %s", target);
6162
this.requestInterceptors =
6263
checkNotNull(requestInterceptors, "requestInterceptors for %s", target);
64+
this.responseInterceptors =
65+
checkNotNull(responseInterceptors, "responseInterceptors for %s", target);
6366
this.logger = checkNotNull(logger, "logger for %s", target);
6467
this.logLevel = checkNotNull(logLevel, "logLevel for %s", target);
6568
this.metadata = checkNotNull(metadata, "metadata for %s", target);
@@ -130,9 +133,19 @@ Object executeAndDecode(RequestTemplate template, Options options) throws Throwa
130133
}
131134
long elapsedTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - start);
132135

136+
for (ResponseInterceptor interceptor: responseInterceptors) {
137+
interceptor.beforeDecode(response);
138+
}
139+
140+
if (decoder != null) {
141+
Object object = decoder.decode(response, metadata.returnType());
142+
143+
for (ResponseInterceptor interceptor: responseInterceptors) {
144+
interceptor.afterDecode(object);
145+
}
133146

134-
if (decoder != null)
135-
return decoder.decode(response, metadata.returnType());
147+
return object;
148+
}
136149

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

146-
return resultFuture.join();
159+
Object object = resultFuture.join();
160+
for (ResponseInterceptor interceptor: responseInterceptors) {
161+
interceptor.afterDecode(object);
162+
}
163+
return object;
147164
} catch (CompletionException e) {
148165
Throwable cause = e.getCause();
149166
if (cause != null)
@@ -179,6 +196,7 @@ static class Factory {
179196
private final Client client;
180197
private final Retryer retryer;
181198
private final List<RequestInterceptor> requestInterceptors;
199+
private final List<ResponseInterceptor> responseInterceptors;
182200
private final Logger logger;
183201
private final Logger.Level logLevel;
184202
private final boolean dismiss404;
@@ -187,11 +205,13 @@ static class Factory {
187205
private final boolean forceDecoding;
188206

189207
Factory(Client client, Retryer retryer, List<RequestInterceptor> requestInterceptors,
208+
List<ResponseInterceptor> responseInterceptors,
190209
Logger logger, Logger.Level logLevel, boolean dismiss404, boolean closeAfterDecode,
191210
ExceptionPropagationPolicy propagationPolicy, boolean forceDecoding) {
192211
this.client = checkNotNull(client, "client");
193212
this.retryer = checkNotNull(retryer, "retryer");
194213
this.requestInterceptors = checkNotNull(requestInterceptors, "requestInterceptors");
214+
this.responseInterceptors = checkNotNull(responseInterceptors, "responseInterceptors");
195215
this.logger = checkNotNull(logger, "logger");
196216
this.logLevel = checkNotNull(logLevel, "logLevel");
197217
this.dismiss404 = dismiss404;
@@ -206,8 +226,8 @@ public MethodHandler create(Target<?> target,
206226
Options options,
207227
Decoder decoder,
208228
ErrorDecoder errorDecoder) {
209-
return new SynchronousMethodHandler(target, client, retryer, requestInterceptors, logger,
210-
logLevel, md, buildTemplateFromArgs, options, decoder,
229+
return new SynchronousMethodHandler(target, client, retryer, requestInterceptors,
230+
responseInterceptors, logger, logLevel, md, buildTemplateFromArgs, options, decoder,
211231
errorDecoder, dismiss404, closeAfterDecode, propagationPolicy, forceDecoding);
212232
}
213233
}

0 commit comments

Comments
 (0)