@@ -20,67 +20,70 @@ package retrofit2
20
20
21
21
import kotlinx.coroutines.Dispatchers
22
22
import kotlinx.coroutines.suspendCancellableCoroutine
23
- import java.lang.reflect.ParameterizedType
24
- import kotlin.coroutines.intrinsics.COROUTINE_SUSPENDED
25
- import kotlin.coroutines.intrinsics.intercepted
26
- import kotlin.coroutines.intrinsics.suspendCoroutineUninterceptedOrReturn
23
+ import kotlinx.coroutines.withContext
27
24
import kotlin.coroutines.resume
28
25
import kotlin.coroutines.resumeWithException
29
26
30
27
inline fun <reified T : Any > Retrofit.create (): T = create(T ::class .java)
31
28
32
29
suspend fun <T : Any > Call<T>.await (): T {
33
- return suspendCancellableCoroutine { continuation ->
34
- continuation.invokeOnCancellation {
35
- cancel()
36
- }
37
- enqueue(object : Callback <T > {
38
- override fun onResponse (call : Call <T >, response : Response <T >) {
39
- if (response.isSuccessful) {
40
- val body = response.body()
41
- if (body == null ) {
42
- val invocation = call.request().tag(Invocation ::class .java)!!
43
- val method = invocation.method()
44
- val e = KotlinNullPointerException (" Response from " +
30
+ // TODO: a better solution for off-main-thread call factories than this.
31
+ return withContext(Dispatchers .Default ) {
32
+ suspendCancellableCoroutine { continuation ->
33
+ continuation.invokeOnCancellation {
34
+ cancel()
35
+ }
36
+ enqueue(object : Callback <T > {
37
+ override fun onResponse (call : Call <T >, response : Response <T >) {
38
+ if (response.isSuccessful) {
39
+ val body = response.body()
40
+ if (body == null ) {
41
+ val invocation = call.request().tag(Invocation ::class .java)!!
42
+ val method = invocation.method()
43
+ val e = KotlinNullPointerException (" Response from " +
45
44
method.declaringClass.name +
46
45
' .' +
47
46
method.name +
48
47
" was null but response body type was declared as non-null" )
49
- continuation.resumeWithException(e)
48
+ continuation.resumeWithException(e)
49
+ } else {
50
+ continuation.resume(body)
51
+ }
50
52
} else {
51
- continuation.resume(body )
53
+ continuation.resumeWithException( HttpException (response) )
52
54
}
53
- } else {
54
- continuation.resumeWithException(HttpException (response))
55
55
}
56
- }
57
56
58
- override fun onFailure (call : Call <T >, t : Throwable ) {
59
- continuation.resumeWithException(t)
60
- }
61
- })
57
+ override fun onFailure (call : Call <T >, t : Throwable ) {
58
+ continuation.resumeWithException(t)
59
+ }
60
+ })
61
+ }
62
62
}
63
63
}
64
64
65
65
@JvmName(" awaitNullable" )
66
66
suspend fun <T : Any > Call<T?>.await (): T ? {
67
- return suspendCancellableCoroutine { continuation ->
68
- continuation.invokeOnCancellation {
69
- cancel()
70
- }
71
- enqueue(object : Callback <T ?> {
72
- override fun onResponse (call : Call <T ?>, response : Response <T ?>) {
73
- if (response.isSuccessful) {
74
- continuation.resume(response.body())
75
- } else {
76
- continuation.resumeWithException(HttpException (response))
77
- }
67
+ // TODO: a better solution for off-main-thread call factories than this.
68
+ return withContext(Dispatchers .Default ) {
69
+ suspendCancellableCoroutine { continuation ->
70
+ continuation.invokeOnCancellation {
71
+ cancel()
78
72
}
73
+ enqueue(object : Callback <T ?> {
74
+ override fun onResponse (call : Call <T ?>, response : Response <T ?>) {
75
+ if (response.isSuccessful) {
76
+ continuation.resume(response.body())
77
+ } else {
78
+ continuation.resumeWithException(HttpException (response))
79
+ }
80
+ }
79
81
80
- override fun onFailure (call : Call <T ?>, t : Throwable ) {
81
- continuation.resumeWithException(t)
82
- }
83
- })
82
+ override fun onFailure (call : Call <T ?>, t : Throwable ) {
83
+ continuation.resumeWithException(t)
84
+ }
85
+ })
86
+ }
84
87
}
85
88
}
86
89
@@ -91,36 +94,21 @@ suspend fun Call<Unit>.await() {
91
94
}
92
95
93
96
suspend fun <T > Call<T>.awaitResponse (): Response <T > {
94
- return suspendCancellableCoroutine { continuation ->
95
- continuation.invokeOnCancellation {
96
- cancel()
97
- }
98
- enqueue(object : Callback <T > {
99
- override fun onResponse (call : Call <T >, response : Response <T >) {
100
- continuation.resume(response)
97
+ // TODO: a better solution for off-main-thread call factories than this.
98
+ return withContext(Dispatchers .Default ) {
99
+ suspendCancellableCoroutine { continuation ->
100
+ continuation.invokeOnCancellation {
101
+ cancel()
101
102
}
103
+ enqueue(object : Callback <T > {
104
+ override fun onResponse (call : Call <T >, response : Response <T >) {
105
+ continuation.resume(response)
106
+ }
102
107
103
- override fun onFailure (call : Call <T >, t : Throwable ) {
104
- continuation.resumeWithException(t)
105
- }
106
- })
107
- }
108
- }
109
-
110
- /* *
111
- * Force the calling coroutine to suspend before throwing [this].
112
- *
113
- * This is needed when a checked exception is synchronously caught in a [java.lang.reflect.Proxy]
114
- * invocation to avoid being wrapped in [java.lang.reflect.UndeclaredThrowableException].
115
- *
116
- * The implementation is derived from:
117
- * https://github.com/Kotlin/kotlinx.coroutines/pull/1667#issuecomment-556106349
118
- */
119
- internal suspend fun Exception.suspendAndThrow (): Nothing {
120
- suspendCoroutineUninterceptedOrReturn<Nothing > { continuation ->
121
- Dispatchers .Default .dispatch(continuation.context) {
122
- continuation.intercepted().resumeWithException(this @suspendAndThrow)
108
+ override fun onFailure (call : Call <T >, t : Throwable ) {
109
+ continuation.resumeWithException(t)
110
+ }
111
+ })
123
112
}
124
- COROUTINE_SUSPENDED
125
113
}
126
114
}
0 commit comments