title: How to create a call adapter for suspending functions in Retrofit?
body: <p>I need to create a retrofit call adapter which can handle such network calls:</p>
  
  <pre><code>@GET("user")
  suspend fun getUser(): MyResponseWrapper&lt;User&gt;
  </code></pre>
  
  <p>I want it to work with Kotlin Coroutines without using <code>Deferred</code>. I have already have a successful implementation using <code>Deferred</code>, which can handle methods such as:</p>
  
  <pre><code>@GET("user")
  fun getUser(): Deferred&lt;MyResponseWrapper&lt;User&gt;&gt;
  </code></pre>
  
  <p>But I want the ability make the function a suspending function and remove the <code>Deferred</code> wrapper.</p>
  
  <p>With suspending functions, Retrofit works as if there is a <code>Call</code> wrapper around the return type, so <code>suspend fun getUser(): User</code> is treated as <code>fun getUser(): Call&lt;User&gt;</code></p>
  
  <h3>My Implementation</h3>
  
  <p>I have tried to create a call adapter which tries to handle this. Here is my implementation so far:</p>
  
  <p><strong>Factory</strong></p>
  
  <pre><code>class MyWrapperAdapterFactory : CallAdapter.Factory() {
  
      override fun get(returnType: Type, annotations: Array&lt;Annotation&gt;, retrofit: Retrofit): CallAdapter&lt;*, *&gt;? {
  
          val rawType = getRawType(returnType)
  
          if (rawType == Call::class.java) {
  
              returnType as? ParameterizedType
                  ?: throw IllegalStateException("$returnType must be parameterized")
  
              val containerType = getParameterUpperBound(0, returnType)
  
              if (getRawType(containerType) != MyWrapper::class.java) {
                  return null
              }
  
              containerType as? ParameterizedType
                  ?: throw IllegalStateException("MyWrapper must be parameterized")
  
              val successBodyType = getParameterUpperBound(0, containerType)
              val errorBodyType = getParameterUpperBound(1, containerType)
  
              val errorBodyConverter = retrofit.nextResponseBodyConverter&lt;Any&gt;(
                  null,
                  errorBodyType,
                  annotations
              )
  
              return MyWrapperAdapter&lt;Any, Any&gt;(successBodyType, errorBodyConverter)
          }
          return null
      }
  </code></pre>
  
  <p><strong>Adapter</strong></p>
  
  <pre><code>class MyWrapperAdapter&lt;T : Any&gt;(
      private val successBodyType: Type
  ) : CallAdapter&lt;T, MyWrapper&lt;T&gt;&gt; {
  
      override fun adapt(call: Call&lt;T&gt;): MyWrapper&lt;T&gt; {
          return try {
              call.execute().toMyWrapper&lt;T&gt;()
          } catch (e: IOException) {
              e.toNetworkErrorWrapper()
          }
      }
  
      override fun responseType(): Type = successBodyType
  }
  </code></pre>
  
  <pre><code>runBlocking {
    val user: MyWrapper&lt;User&gt; = service.getUser()
  }
  </code></pre>
  
  <p>Everything works as expected using this implementation, but just before the result of the network call is delivered to the <code>user</code> variable, I get the following error:</p>
  
  <pre><code>java.lang.ClassCastException: com.myproject.MyWrapper cannot be cast to retrofit2.Call
  
      at retrofit2.HttpServiceMethod$SuspendForBody.adapt(HttpServiceMethod.java:185)
      at retrofit2.HttpServiceMethod.invoke(HttpServiceMethod.java:132)
      at retrofit2.Retrofit$1.invoke(Retrofit.java:149)
      at com.sun.proxy.$Proxy6.getText(Unknown Source)
      ...
  </code></pre>
  
  <p>From Retrofit's source, here is the piece of code at <code>HttpServiceMethod.java:185</code>:</p>
  
  <pre class="lang-java prettyprint-override"><code>    @Override protected Object adapt(Call&lt;ResponseT&gt; call, Object[] args) {
        call = callAdapter.adapt(call); // ERROR OCCURS HERE
  
        //noinspection unchecked Checked by reflection inside RequestFactory.
        Continuation&lt;ResponseT&gt; continuation = (Continuation&lt;ResponseT&gt;) args[args.length - 1];
        return isNullable
            ? KotlinExtensions.awaitNullable(call, continuation)
            : KotlinExtensions.await(call, continuation);
      }
  </code></pre>
  
  <p>I'm not sure how to handle this error. Is there a way to fix?</p>