Skip to content

Commit ad84303

Browse files
authored
Reject suspend function with Call return type (#4013)
1 parent 8ce895d commit ad84303

File tree

2 files changed

+28
-0
lines changed

2 files changed

+28
-0
lines changed

retrofit/kotlin-test/src/test/java/retrofit2/KotlinSuspendTest.kt

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ class KotlinSuspendTest {
5656
@Path("b") b: String,
5757
@Path("c") c: String
5858
): String
59+
60+
@GET("/") suspend fun bodyWithCallType(): Call<String>
5961
}
6062

6163
@Test fun body() {
@@ -353,6 +355,25 @@ class KotlinSuspendTest {
353355
}
354356
}
355357

358+
@Test fun rejectCallReturnTypeWhenUsingSuspend() {
359+
val retrofit = Retrofit.Builder()
360+
.baseUrl(server.url("/"))
361+
.addConverterFactory(ToStringConverterFactory())
362+
.build()
363+
val example = retrofit.create(Service::class.java)
364+
365+
try {
366+
runBlocking { example.bodyWithCallType() }
367+
fail()
368+
} catch (e: IllegalArgumentException) {
369+
assertThat(e).hasMessage(
370+
"Suspend functions should not return Call, as they already execute asynchronously.\n" +
371+
"Change its return type to class java.lang.String\n" +
372+
" for method Service.bodyWithCallType"
373+
)
374+
}
375+
}
376+
356377
@Suppress("EXPERIMENTAL_OVERRIDE")
357378
private object DirectUnconfinedDispatcher : CoroutineDispatcher() {
358379
override fun isDispatchNeeded(context: CoroutineContext): Boolean = false

retrofit/src/main/java/retrofit2/HttpServiceMethod.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,13 @@ static <ResponseT, ReturnT> HttpServiceMethod<ResponseT, ReturnT> parseAnnotatio
5353
responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
5454
continuationWantsResponse = true;
5555
} else {
56+
if (getRawType(responseType) == Call.class) {
57+
throw methodError(
58+
method,
59+
"Suspend functions should not return Call, as they already execute asynchronously.\n" +
60+
"Change its return type to %s", Utils.getParameterUpperBound(0, (ParameterizedType) responseType));
61+
}
62+
5663
continuationIsUnit = Utils.isUnit(responseType);
5764
// TODO figure out if type is nullable or not
5865
// Metadata metadata = method.getDeclaringClass().getAnnotation(Metadata.class)

0 commit comments

Comments
 (0)