2727/**
2828 * A Failsafe wrapped Retrofit {@link Call}. Supports synchronous and asynchronous executions, and cancellation.
2929 *
30- * @param <T > response type
30+ * @param <R > response type
3131 * @author Jonathan Halterman
3232 */
33- public final class FailsafeCall <T > {
34- private final FailsafeExecutor <Response <T >> failsafe ;
35- private final retrofit2 .Call <T > initialCall ;
33+ public final class FailsafeCall <R > {
34+ private final FailsafeExecutor <Response <R >> failsafe ;
35+ private final retrofit2 .Call <R > initialCall ;
3636
37- private volatile Call <Response <T >> failsafeCall ;
38- private volatile CompletableFuture <Response <T >> failsafeFuture ;
37+ private volatile Call <Response <R >> failsafeCall ;
38+ private volatile CompletableFuture <Response <R >> failsafeFuture ;
3939 private AtomicBoolean cancelled = new AtomicBoolean ();
4040 private AtomicBoolean executed = new AtomicBoolean ();
4141
42- private FailsafeCall (retrofit2 .Call <T > call , FailsafeExecutor <Response <T >> failsafe ) {
43- this .initialCall = call ;
42+ private FailsafeCall (FailsafeExecutor <Response <R >> failsafe , retrofit2 .Call <R > call ) {
4443 this .failsafe = failsafe ;
44+ this .initialCall = call ;
45+ }
46+
47+ public static final class FailsafeCallBuilder <R > {
48+ private FailsafeExecutor <Response <R >> failsafe ;
49+
50+ private FailsafeCallBuilder (FailsafeExecutor <Response <R >> failsafe ) {
51+ this .failsafe = failsafe ;
52+ }
53+
54+ public <P extends Policy <Response <R >>> FailsafeCallBuilder <R > compose (P innerPolicy ) {
55+ failsafe = failsafe .compose (innerPolicy );
56+ return this ;
57+ }
58+
59+ public FailsafeCall <R > compose (retrofit2 .Call <R > call ) {
60+ return new FailsafeCall <>(failsafe , call );
61+ }
4562 }
4663
4764 /**
48- * Returns a FailsafeCall for the {@code call}, {@code outerPolicy} and {@code policies}. See {@link
49- * Failsafe#with(Policy, Policy[])} for docs on how policy composition works.
65+ * Returns a FailsafeCallBuilder for the {@code outerPolicy} and {@code policies}. See {@link Failsafe#with(Policy,
66+ * Policy[])} for docs on how policy composition works.
5067 *
51- * @param <T> response type
68+ * @param <R> result type
5269 * @param <P> policy type
5370 * @throws NullPointerException if {@code call} or {@code outerPolicy} are null
5471 */
5572 @ SafeVarargs
56- public static <T , P extends Policy <Response <T >>> FailsafeCall <T > of (retrofit2 .Call <T > call , P outerPolicy ,
57- P ... policies ) {
58- return of (call , Failsafe .with (outerPolicy , policies ));
73+ public static <R , P extends Policy <Response <R >>> FailsafeCallBuilder <R > with (P outerPolicy , P ... policies ) {
74+ return new FailsafeCallBuilder <>(Failsafe .with (outerPolicy , policies ));
5975 }
6076
6177 /**
62- * Returns a FailsafeCall for the {@code call} and {@code failsafeExecutor}.
78+ * Returns a FailsafeCallBuilder for the {@code failsafeExecutor}.
6379 *
64- * @param <T> response type
65- * @throws NullPointerException if {@code call} or {@code failsafeExecutor} are null
80+ * @param <R> result type
81+ * @throws NullPointerException if {@code failsafeExecutor} is null
6682 */
67- public static <T > FailsafeCall < T > of ( retrofit2 . Call < T > call , FailsafeExecutor <Response <T >> failsafeExecutor ) {
68- return new FailsafeCall <>(Assert . notNull ( call , "call" ), Assert .notNull (failsafeExecutor , "failsafeExecutor" ));
83+ public static <R > FailsafeCallBuilder < R > with ( FailsafeExecutor <Response <R >> failsafeExecutor ) {
84+ return new FailsafeCallBuilder <>(Assert .notNull (failsafeExecutor , "failsafeExecutor" ));
6985 }
7086
7187 /**
@@ -83,8 +99,8 @@ public void cancel() {
8399 /**
84100 * Returns a clone of the FailsafeCall.
85101 */
86- public FailsafeCall <T > clone () {
87- return FailsafeCall . of ( initialCall .clone (), failsafe );
102+ public FailsafeCall <R > clone () {
103+ return new FailsafeCall <>( failsafe , initialCall .clone ());
88104 }
89105
90106 /**
@@ -95,7 +111,7 @@ public FailsafeCall<T> clone() {
95111 * @throws FailsafeException if the execution fails with a checked Exception. {@link FailsafeException#getCause()} can
96112 * be used to learn the underlying checked exception.
97113 */
98- public Response <T > execute () throws IOException {
114+ public Response <R > execute () throws IOException {
99115 Assert .isTrue (executed .compareAndSet (false , true ), "already executed" );
100116
101117 failsafeCall = failsafe .newCall (ctx -> {
@@ -114,22 +130,22 @@ public Response<T> execute() throws IOException {
114130 /**
115131 * Executes the call asynchronously until a successful result is returned or the configured policies are exceeded.
116132 */
117- public CompletableFuture <Response <T >> executeAsync () {
133+ public CompletableFuture <Response <R >> executeAsync () {
118134 if (!executed .compareAndSet (false , true )) {
119- CompletableFuture <Response <T >> result = new CompletableFuture <>();
135+ CompletableFuture <Response <R >> result = new CompletableFuture <>();
120136 result .completeExceptionally (new IllegalStateException ("already executed" ));
121137 return result ;
122138 }
123139
124140 failsafeFuture = failsafe .getAsyncExecution (exec -> {
125- prepareCall (exec ).enqueue (new Callback <T >() {
141+ prepareCall (exec ).enqueue (new Callback <R >() {
126142 @ Override
127- public void onResponse (retrofit2 .Call <T > call , Response <T > response ) {
143+ public void onResponse (retrofit2 .Call <R > call , Response <R > response ) {
128144 exec .recordResult (response );
129145 }
130146
131147 @ Override
132- public void onFailure (retrofit2 .Call <T > call , Throwable throwable ) {
148+ public void onFailure (retrofit2 .Call <R > call , Throwable throwable ) {
133149 exec .recordException (throwable );
134150 }
135151 });
@@ -152,8 +168,8 @@ public boolean isExecuted() {
152168 return executed .get ();
153169 }
154170
155- private retrofit2 .Call <T > prepareCall (ExecutionContext <Response <T >> ctx ) {
156- retrofit2 .Call <T > call = ctx .isFirstAttempt () ? initialCall : initialCall .clone ();
171+ private retrofit2 .Call <R > prepareCall (ExecutionContext <Response <R >> ctx ) {
172+ retrofit2 .Call <R > call = ctx .isFirstAttempt () ? initialCall : initialCall .clone ();
157173
158174 // Propagate cancellation to the call
159175 ctx .onCancel (() -> {
0 commit comments