Why can't I use the interface as the generic type in this Rx transformer?

Viewed 103

I have the following data classes in Kotlin as reference:

interface GenericResponse {

    val error: Error?

    fun hasErrorObject(): Boolean = error != null
}

data class LoginResponse(
    val name: String,
    val auth: String,
    @SerializedName("error") override val error: Error? = null
) : GenericResponse

LoginResponse implements GenericResponse. I'm using a Retrofit API in the following manner:

@POST("******")
fun createSession(@Body body: LoginBody): Single<Response<LoginResponse>>

Furthermore, I use a transformer to extract the error from the LoginResponse if it exists as shown below:

class ExceptionTransformers {
    fun <T> wrapRetrofitExceptionSingle(): (Single<Response<T>>) -> Single<T> {
        return { it: Single<Response<T>> ->
            it.flatMap { response: Response<T> ->
                if (response.code() == 200 && response.body() != null) {
                    val genericResponse = response.body() as GenericResponse
                    if (genericResponse.hasErrorObject()) {
                        Single.error { MyException(genericResponse.error!!) }
                    } else {
                        Single.just(response.body()!!)
                    }
                } else {
                    Single.error { UnknownError() }
                }
            }
        }
    }
}

As you can see, I have to cast the response body into a GenericResponse instance and then continue the login in the ExceptionTransformer. My question is this: Is there a way of using the return type as GenericResponse rather than type T (the generic)? I have tried to do that - but ran into a number of errors when using it like this:

fun createSession(loginBody: LoginBody): Single<LoginResponse> {
    return apiService.createSession(loginBody)
          .compose(exceptionTransformers.wrapRetrofitExceptionSingle())
}
1 Answers

From what you have specified, it seems T will always be a subtype of GenericResponse - adding a type parameter constraint may be what you want.

fun <T : GenericResponse> wrapRetrofitExceptionSingle() {
    ...
}
Related