Skip to content

Commit bcf0c8f

Browse files
TaoJing96velo
andauthored
support method option and add UT (#1881)
* support method option and add UT * format code style * add Experimental annotation * Added @experimental to new method --------- Co-authored-by: Marvin Froeder <velo@users.noreply.github.com>
1 parent 16f600e commit bcf0c8f

File tree

4 files changed

+86
-2
lines changed

4 files changed

+86
-2
lines changed

core/src/main/java/feign/Request.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
package feign;
1515

1616
import static feign.Util.checkNotNull;
17+
import static feign.Util.getThreadIdentifier;
1718
import static feign.Util.valuesOrEmpty;
1819
import java.io.Serializable;
1920
import java.net.HttpURLConnection;
@@ -22,8 +23,10 @@
2223
import java.util.Arrays;
2324
import java.util.Collection;
2425
import java.util.Collections;
26+
import java.util.HashMap;
2527
import java.util.Map;
2628
import java.util.Optional;
29+
import java.util.concurrent.ConcurrentHashMap;
2730
import java.util.concurrent.TimeUnit;
2831

2932
/**
@@ -303,6 +306,35 @@ public static class Options {
303306
private final long readTimeout;
304307
private final TimeUnit readTimeoutUnit;
305308
private final boolean followRedirects;
309+
private final Map<String, Map<String, Options>> threadToMethodOptions;
310+
311+
/**
312+
* Get an Options by methodName
313+
*
314+
* @param methodName it's your FeignInterface method name.
315+
* @return method Options
316+
*/
317+
@Experimental
318+
public Options getMethodOptions(String methodName) {
319+
Map<String, Options> methodOptions =
320+
threadToMethodOptions.getOrDefault(getThreadIdentifier(), new HashMap<>());
321+
return methodOptions.getOrDefault(methodName, this);
322+
}
323+
324+
/**
325+
* Set methodOptions by methodKey and options
326+
*
327+
* @param methodName it's your FeignInterface method name.
328+
* @param options it's the Options for this method.
329+
*/
330+
@Experimental
331+
public void setMethodOptions(String methodName, Options options) {
332+
String threadIdentifier = getThreadIdentifier();
333+
Map<String, Request.Options> methodOptions =
334+
threadToMethodOptions.getOrDefault(threadIdentifier, new HashMap<>());
335+
threadToMethodOptions.put(threadIdentifier, methodOptions);
336+
methodOptions.put(methodName, options);
337+
}
306338

307339
/**
308340
* Creates a new Options instance.
@@ -338,6 +370,7 @@ public Options(long connectTimeout, TimeUnit connectTimeoutUnit,
338370
this.readTimeout = readTimeout;
339371
this.readTimeoutUnit = readTimeoutUnit;
340372
this.followRedirects = followRedirects;
373+
this.threadToMethodOptions = new ConcurrentHashMap<>();
341374
}
342375

343376
/**

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,13 +128,13 @@ Request targetRequest(RequestTemplate template) {
128128

129129
Options findOptions(Object[] argv) {
130130
if (argv == null || argv.length == 0) {
131-
return this.options;
131+
return this.options.getMethodOptions(metadata.method().getName());
132132
}
133133
return Stream.of(argv)
134134
.filter(Options.class::isInstance)
135135
.map(Options.class::cast)
136136
.findFirst()
137-
.orElse(this.options);
137+
.orElse(this.options.getMethodOptions(metadata.method().getName()));
138138
}
139139

140140
static class Factory implements MethodHandler.Factory<Object> {

core/src/main/java/feign/Util.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,4 +400,9 @@ public static List<Field> allFields(Class<?> clazz) {
400400
return fields;
401401
}
402402

403+
public static String getThreadIdentifier() {
404+
Thread currentThread = Thread.currentThread();
405+
return currentThread.getThreadGroup() + "_" + currentThread.getName() + "_"
406+
+ currentThread.getId();
407+
}
403408
}

core/src/test/java/feign/OptionsTest.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818
import org.junit.Test;
1919
import org.junit.rules.ExpectedException;
2020
import java.net.SocketTimeoutException;
21+
import java.util.concurrent.CountDownLatch;
2122
import java.util.concurrent.TimeUnit;
23+
import java.util.concurrent.atomic.AtomicReference;
2224
import okhttp3.mockwebserver.MockResponse;
2325
import okhttp3.mockwebserver.MockWebServer;
2426
import static org.assertj.core.api.Assertions.assertThat;
@@ -87,4 +89,48 @@ public void normalResponseForChildOptionsTest() {
8789

8890
assertThat(api.getChildOptions(new ChildOptions(1000, 4 * 1000))).isEqualTo("foo");
8991
}
92+
93+
@Test
94+
public void socketTimeoutWithMethodOptionsTest() throws Exception {
95+
final MockWebServer server = new MockWebServer();
96+
server.enqueue(new MockResponse().setBody("foo").setBodyDelay(2, TimeUnit.SECONDS));
97+
Request.Options options = new Request.Options(1000, 3000);
98+
final OptionsInterface api = Feign.builder()
99+
.options(options)
100+
.target(OptionsInterface.class, server.url("/").toString());
101+
102+
AtomicReference<Exception> exceptionAtomicReference = new AtomicReference<>();
103+
Thread thread = new Thread(() -> {
104+
try {
105+
options.setMethodOptions("get", new Request.Options(1000, 1000));
106+
api.get();
107+
} catch (Exception exception) {
108+
exceptionAtomicReference.set(exception);
109+
}
110+
});
111+
thread.start();
112+
thread.join();
113+
thrown.expect(FeignException.class);
114+
thrown.expectCause(CoreMatchers.isA(SocketTimeoutException.class));
115+
throw exceptionAtomicReference.get();
116+
}
117+
118+
@Test
119+
public void normalResponseWithMethodOptionsTest() throws Exception {
120+
final MockWebServer server = new MockWebServer();
121+
server.enqueue(new MockResponse().setBody("foo").setBodyDelay(2, TimeUnit.SECONDS));
122+
Request.Options options = new Request.Options(1000, 1000);
123+
final OptionsInterface api = Feign.builder()
124+
.options(options)
125+
.target(OptionsInterface.class, server.url("/").toString());
126+
127+
CountDownLatch countDownLatch = new CountDownLatch(1);
128+
Thread thread = new Thread(() -> {
129+
options.setMethodOptions("get", new Request.Options(1000, 3000));
130+
api.get();
131+
countDownLatch.countDown();
132+
});
133+
thread.start();
134+
thread.join();
135+
}
90136
}

0 commit comments

Comments
 (0)