title: Retrofit & Moshi: Get request with sealed class & generics - Is it possible?
body: <p>I have a sealed class for state handling of my Retrofit responses. It's members take a generic type. I would like to get Retrofit to be able to return the proper object, but I am stuck at this error: <code>Unable to create converter for com.my.app.DataResult&lt;?&gt; - Cannot serialize abstract class com.my.app.DataResult</code></p>
  
  <p>This is my DataResult class:</p>
  
  <pre><code>sealed class DataResult&lt;out T&gt; {
  
      data class Success&lt;out T&gt;(val data: T?) : DataResult&lt;T&gt;()
  
      data class Error&lt;out T&gt;(val code: Int? = null, val error: Exception? = null) : DataResult&lt;T&gt;()
      object NetworkError : DataResult&lt;Nothing&gt;()
  
      fun isSuccess() = this is Success&lt;*&gt;
      fun isError() = this is Error&lt;*&gt;
      fun data() = if (isSuccess()) (this as Success&lt;T&gt;).data else null
  }
  
  fun successResult() = DataResult.Success(null)
  fun &lt;T&gt; successResult(data: T?) = DataResult.Success(data)
  fun errorResult() = DataResult.Error&lt;Nothing&gt;(null)
  </code></pre>
  
  <p>This is the rest of my current implementation: </p>
  
  <pre><code>class NetworkClient(private val httpClient: HttpClient) {
  
      private val baseUrl: String = "some url"
  
      private val retrofit = Retrofit.Builder()
          .baseUrl(mockend)
          .addCallAdapterFactory(MyCallAdapterFactory())
          .addConverterFactory(MoshiConverterFactory.create())
          .client(httpClient.get())
          .build()
  
      private val apiService: ApiService = retrofit.create(StaApiService::class.java)
      suspend fun &lt;T&gt; sendGet(endPoint: EndPoint, input: String): DataResult&lt;T&gt; {
          val result = apiService.sendGetRequest&lt;T&gt;(endPoint.stringValue, queryMapOf(Pair("query", input)))
  
          when (result) {
              // do stuff here?
          }
          return result
      }
  }
  
  </code></pre>
  
  <pre><code>interface ApiService {
  
      @GET
      suspend fun &lt;T&gt; sendGetRequest(
          @Url url: String,
          @QueryMap parameters: Map&lt;String, String&gt;): DataResult&lt;T&gt;
  
      @GET
      suspend fun &lt;T&gt; sendGetListRequest(
          @Url url: String,
          @QueryMap parameters: Map&lt;String, String&gt;): DataResult&lt;List&lt;T&gt;&gt;
  }
  </code></pre>
  
  <pre><code>abstract class CallDelegate&lt;TIn, TOut&gt;(
      protected val proxy: Call&lt;TIn&gt;
  ) : Call&lt;TOut&gt; {
      override fun execute(): Response&lt;TOut&gt; = throw NotImplementedError()
      final override fun enqueue(callback: Callback&lt;TOut&gt;) = enqueueImpl(callback)
      final override fun clone(): Call&lt;TOut&gt; = cloneImpl()
      override fun cancel() = proxy.cancel()
      override fun request(): Request = proxy.request()
      override fun isExecuted() = proxy.isExecuted
      override fun isCanceled() = proxy.isCanceled
      abstract fun enqueueImpl(callback: Callback&lt;TOut&gt;)
      abstract fun cloneImpl(): Call&lt;TOut&gt;
  }
  </code></pre>
  
  <pre><code>class ResultCall&lt;T&gt;(proxy: Call&lt;T&gt;) : CallDelegate&lt;T, DataResult&lt;T&gt;&gt;(proxy) {
      override fun enqueueImpl(callback: Callback&lt;DataResult&lt;T&gt;&gt;) = proxy.enqueue(object : Callback&lt;T&gt; {
          override fun onResponse(call: Call&lt;T&gt;, response: Response&lt;T&gt;) {
              val code = response.code()
              val result: DataResult&lt;T&gt; = if (code in 200 until 300) {
                  val body = response.body()
                  DataResult.Success(body)
              } else {
                  DataResult.Error(code)
              }
  
              callback.onResponse(this@ResultCall, Response.success(result))
          }
  
          override fun onFailure(call: Call&lt;T&gt;, t: Throwable) {
              val result: DataResult&lt;Nothing&gt; = if (t is IOException) {
                  DataResult.NetworkError
              } else {
                  DataResult.Error(null)
              }
  
              callback.onResponse(this@ResultCall, Response.success(result))
          }
      })
  
      override fun cloneImpl() = ResultCall(proxy.clone())
  }
  </code></pre>
  
  <pre><code>class ResultAdapter(
      private val type: Type
  ) : CallAdapter&lt;Type, Call&lt;DataResult&lt;Type&gt;&gt;&gt; {
      override fun responseType() = type
      override fun adapt(call: Call&lt;Type&gt;): Call&lt;DataResult&lt;Type&gt;&gt; = ResultCall(call)
  }
  </code></pre>
  
  <pre><code>class MyCallAdapterFactory : CallAdapter.Factory() {
      override fun get(
          returnType: Type,
          annotations: Array&lt;Annotation&gt;,
          retrofit: Retrofit
      ) = when (getRawType(returnType)) {
          Call::class.java -&gt; {
              val callType = getParameterUpperBound(0, returnType as ParameterizedType)
              when (getRawType(callType)) {
                  Result::class.java -&gt; {
                      val resultType = getParameterUpperBound(0, callType as ParameterizedType)
                      ResultAdapter(resultType)
                  }
                  else -&gt; null
              }
          }
          else -&gt; null
      }
  }
  </code></pre>
  
  <p>The above code is largely inspired by <a href="https://stackoverflow.com/a/57816819/8746644">this answer to another question</a>,
  but I'm trying to add Generics to the mix, so I don't have to put every request into the interface by hand. Is it possible or not? I have tried for hours, also tried to build an adapter for the sealed class but failed. Has someone a good resource how this can be done?</p>
  
  <p>As you can also see in the code I'd like to also be able to receive lists. Any tips here are much appreciated too.</p>