Skip to content

Commit bc9948f

Browse files
committed
Merge pull request OpenFeign#387 from padilo/completable_support
Added rx.Completable support
2 parents 5c352a0 + 53cfd0d commit bc9948f

5 files changed

Lines changed: 102 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
### Version 8.17
2+
* Adds support to RxJava Completable via `HystrixFeign` builder with fallback support
3+
* Upgraded hystrix-core to 1.4.26
4+
15
### Version 8.16
26
* Adds `@HeaderMap` annotation to support dynamic header fields and values
37
* Add support for default and static methods on interfaces

hystrix/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ sourceCompatibility = 1.6
44

55
dependencies {
66
compile project(':feign-core')
7-
compile 'com.netflix.hystrix:hystrix-core:1.4.21'
7+
compile 'com.netflix.hystrix:hystrix-core:1.4.26'
88
testCompile 'junit:junit:4.12'
99
testCompile 'org.assertj:assertj-core:1.7.1' // last version supporting JDK 7
1010
testCompile 'com.squareup.okhttp:mockwebserver:2.7.5'

hystrix/src/main/java/feign/hystrix/HystrixDelegatingContract.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
import feign.Contract;
1212
import feign.MethodMetadata;
13+
import rx.Completable;
1314
import rx.Observable;
1415
import rx.Single;
1516

@@ -44,6 +45,8 @@ public List<MethodMetadata> parseAndValidatateMetadata(Class<?> targetType) {
4445
} else if (type instanceof ParameterizedType && ((ParameterizedType) type).getRawType().equals(Single.class)) {
4546
Type actualType = resolveLastTypeParameter(type, Single.class);
4647
metadata.returnType(actualType);
48+
} else if (type instanceof ParameterizedType && ((ParameterizedType) type).getRawType().equals(Completable.class)) {
49+
metadata.returnType(void.class);
4750
}
4851
}
4952

hystrix/src/main/java/feign/hystrix/HystrixInvocationHandler.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import feign.InvocationHandlerFactory;
3030
import feign.InvocationHandlerFactory.MethodHandler;
3131
import feign.Target;
32+
import rx.Completable;
3233
import rx.Observable;
3334
import rx.Single;
3435

@@ -117,6 +118,9 @@ protected Object getFallback() {
117118
} else if (isReturnsSingle(method)) {
118119
// Create a cold Observable as a Single
119120
return ((Single) result).toObservable().toBlocking().first();
121+
} else if (isReturnsCompletable(method)) {
122+
((Completable) result).await();
123+
return null;
120124
} else {
121125
return result;
122126
}
@@ -138,10 +142,16 @@ protected Object getFallback() {
138142
} else if (isReturnsSingle(method)) {
139143
// Create a cold Observable as a Single
140144
return hystrixCommand.toObservable().toSingle();
145+
} else if(isReturnsCompletable(method)) {
146+
return hystrixCommand.toObservable().toCompletable();
141147
}
142148
return hystrixCommand.execute();
143149
}
144150

151+
private boolean isReturnsCompletable(Method method) {
152+
return Completable.class.isAssignableFrom(method.getReturnType());
153+
}
154+
145155
private boolean isReturnsHystrixCommand(Method method) {
146156
return HystrixCommand.class.isAssignableFrom(method.getReturnType());
147157
}

hystrix/src/test/java/feign/hystrix/HystrixBuilderTest.java

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import feign.Target;
2424
import feign.Target.HardCodedTarget;
2525
import feign.gson.GsonDecoder;
26+
import rx.Completable;
2627
import rx.Observable;
2728
import rx.Single;
2829
import rx.observers.TestSubscriber;
@@ -384,6 +385,81 @@ public void rxSingleListFallback() {
384385
assertThat(testSubscriber.getOnNextEvents().get(0)).containsExactly("fallback");
385386
}
386387

388+
@Test
389+
public void rxCompletableEmptyBody() {
390+
server.enqueue(new MockResponse());
391+
392+
TestInterface api = target();
393+
394+
Completable completable = api.completable();
395+
396+
assertThat(completable).isNotNull();
397+
assertThat(server.getRequestCount()).isEqualTo(0);
398+
399+
TestSubscriber<String> testSubscriber = new TestSubscriber<String>();
400+
completable.subscribe(testSubscriber);
401+
testSubscriber.awaitTerminalEvent();
402+
403+
testSubscriber.assertCompleted();
404+
testSubscriber.assertNoErrors();
405+
}
406+
407+
@Test
408+
public void rxCompletableWithBody() {
409+
server.enqueue(new MockResponse().setBody("foo"));
410+
411+
TestInterface api = target();
412+
413+
Completable completable = api.completable();
414+
415+
assertThat(completable).isNotNull();
416+
assertThat(server.getRequestCount()).isEqualTo(0);
417+
418+
TestSubscriber<String> testSubscriber = new TestSubscriber<String>();
419+
completable.subscribe(testSubscriber);
420+
testSubscriber.awaitTerminalEvent();
421+
422+
testSubscriber.assertCompleted();
423+
testSubscriber.assertNoErrors();
424+
}
425+
426+
@Test
427+
public void rxCompletableFailWithoutFallback() {
428+
server.enqueue(new MockResponse().setResponseCode(500));
429+
430+
TestInterface api = HystrixFeign.builder()
431+
.target(TestInterface.class, "http://localhost:" + server.getPort());
432+
433+
Completable completable = api.completable();
434+
435+
assertThat(completable).isNotNull();
436+
assertThat(server.getRequestCount()).isEqualTo(0);
437+
438+
TestSubscriber<String> testSubscriber = new TestSubscriber<String>();
439+
completable.subscribe(testSubscriber);
440+
testSubscriber.awaitTerminalEvent();
441+
442+
testSubscriber.assertError(HystrixRuntimeException.class);
443+
}
444+
445+
@Test
446+
public void rxCompletableFallback() {
447+
server.enqueue(new MockResponse().setResponseCode(500));
448+
449+
TestInterface api = target();
450+
451+
Completable completable = api.completable();
452+
453+
assertThat(completable).isNotNull();
454+
assertThat(server.getRequestCount()).isEqualTo(0);
455+
456+
TestSubscriber<String> testSubscriber = new TestSubscriber<String>();
457+
completable.subscribe(testSubscriber);
458+
testSubscriber.awaitTerminalEvent();
459+
460+
testSubscriber.assertCompleted();
461+
}
462+
387463
@Test
388464
public void plainString() {
389465
server.enqueue(new MockResponse().setBody("\"foo\""));
@@ -526,6 +602,9 @@ interface TestInterface {
526602
@RequestLine("GET /")
527603
@Headers("Accept: application/json")
528604
List<String> getList();
605+
606+
@RequestLine("GET /")
607+
Completable completable();
529608
}
530609

531610
class FallbackTestInterface implements TestInterface {
@@ -606,5 +685,10 @@ public List<String> getList() {
606685
fallbackResult.add("fallback");
607686
return fallbackResult;
608687
}
688+
689+
@Override
690+
public Completable completable() {
691+
return Completable.complete();
692+
}
609693
}
610694
}

0 commit comments

Comments
 (0)