Kotlin generics error when changing T to nullable

34 views Asked by At

I have an app where I make an API call with RetroFit and the API response will have a standard format with the actual result in an object in the JSON. Every API call is wrapped in this object:

data class EventResponse<T>(
    val event: EventObject,
    val data: T?,
)

data class EventObject(
    val error: Boolean = false,
    val success: Boolean = false,
    val message: String? = null,
)

The JSON looks like this:

{
    "event": {
        "success": true,
        "error": false,
        "message": "Some message",
    },
    "data": {"someJsonObject":"someValue"},
}

Currently, the app doesn't handle it too well when the data is null. I've tried changing my code to allow nullable objects but then I get a type mismatch error where I call the function and the objects are non-nullable.

For example, take 2 example API calls. 1 returns a list wrapped in the EventResponse, and another just a single object

fun getUser(@Query("user_id") id: String): Single<EventResponse<List<UserRemoteModel>>>
fun getSuperUser(): Single<EventResponse<SuperUserRemoteModel>>

These are called as follows:

ApiCallWrapper.makeCall(api.getUser(userId))

My ApiCallWrapper code is as follows:

object ApiCallWrapper {

    var eventHandler: ((event: EventObject) -> Unit)? = null

    fun <T : Any?> makeCall(apiCall: Single<EventResponse<T?>>): Single<T?> {
        return apiCall.handleResponse(eventHandler)
    }
}

fun <T : Any?> Single<EventResponse<T?>>.handleResponse(eventHandler: ((event: EventObject) -> Unit)?): Single<T?> {
    return this
        .onErrorReturn {
            it.printStackTrace()
            EventResponse.default(error = true, success = false, show = true, message = it.localizedMessage)
        }
        .doOnError { it.printStackTrace() }
        .flatMap { response ->
            eventHandler?.invoke(response.event)

            if (!response.event.success || response.event.error) {
                throw Exception(response.event.message ?: "Unknown error")
            } else {
                Single.just(response.data) // <--- SOURCE OF ERROR
            }
        }
}

So when the data is not null, this all works fine. However, I've changed the API calls that could possible be nullable to the following:

fun getUser(@Query("user_id") id: String): Single<EventResponse<List<UserRemoteModel>?>>

So I'm trying to say that the EventResponse won't be null but the object (List or normal object) can be null. When I make this change to make it nullable, I get an error on all other calls that are NOT nullable:

Type mismatch.
Required:
Single<EventResponse<TypeVariable(T)?>>
Found:
Single<EventResponse<NonNullRemoteModel>>

So its telling me there's a Type Mismatch because it's looking for T? and I'm passing T. This started happening after I changed my ApiCAllWrapper method signature:

-    fun <T : Any?> makeCall(apiCall: Single<EventResponse<T>>): Single<T?> {
+    fun <T : Any?> makeCall(apiCall: Single<EventResponse<T?>>): Single<T?> {

and

-fun <T : Any?> Single<EventResponse<T>>.handleResponse(eventHandler: ((event: EventObject) -> Unit)?): Single<T?> {
+fun <T : Any?> Single<EventResponse<T?>>.handleResponse(eventHandler: ((event: EventObject) -> Unit)?): Single<T?> {

It's a bit complicated to put it all in one post but the main issue is that I get an RxJava error when the data is null and it can stop further API calls, as I am calling all my different endpoints in an initial sync when I log in to the app, so I need to be able to handle this gracefully.

The other option is I find another way to handle my API responses that can support the generic Event format.

Thanks

0

There are 0 answers